2015-12-08 2 views
0

Я работаю над вопросом практического интервью. Проблема состоит в том, чтобы реализовать отсортированный стек, используя только еще один стек для временного хранения.Наследование Java, как переопределить метод в подклассе

Описание реализации: Я расширяю класс Stack для реализации класса SortedStack. Большинство методов класса SortedStack идентичны классу Stack, поэтому мне не нужно их реализовывать. Только метод push отменяется.

В моей реализации я передаю текущий стек, чтобы нажать метод. Мой вопрос: это лучший способ получить доступ к существующему стеку. Могу ли я получить содержимое стека, не передавая его методу push()?

Node.java

public class Node { 
    private int key; 
    private float value; 

    public Node(int key, float value) { 
     this.key = key; 
     this.value = value; 
    } 

    public int getKey() { return key; } 
    public void setKey(int key) { this.key = key; } 

    public float getValue() { return value; } 
    public void setValue(float value) { this.value = value; } 
} 

SortedStack.java

import java.util.Stack; 

public class SortedStack extends Stack { 

    public SortedStack() { 
     super(); 
    } 

    public void push(Stack<Node> mainStack, Node newNode) { 
     Stack<Node> tempStack = new Stack<Node>(); 

     while (!mainStack.isEmpty()) { 
      if (mainStack.peek().getKey() > newNode.getKey()) { 
       tempStack.push(mainStack.pop()); 
      } 
      else { 
       break; 
      } 
     } 

     mainStack.push(newNode); 

     while (!tempStack.isEmpty()) { 
      mainStack.push(tempStack.pop()); 
     } 
    } 

} 

SortedStackApp.java

public class SortedStackApp { 

    public static void main(String[] args) { 

     SortedStack stack = new SortedStack(); 

     stack.push(stack, new Node(10, 1.1f)); 
     stack.push(stack, new Node(80, 1.8f)); 
     stack.push(stack, new Node(50, 1.5f)); 
     stack.push(stack, new Node(90, 1.9f)); 
     stack.push(stack, new Node(20, 1.2f)); 
     stack.push(stack, new Node(30, 1.3f)); 

     Node node = null; 

     while (!stack.isEmpty()) { 
      node = (Node) stack.pop(); 
      System.out.printf("(%d, %3.1f) ", node.getKey(), node.getValue()); 
     } 
     System.out.println(); 
    } 
} 

Stack я s java.util.Stack, как описано в: http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html

+2

Это не очень хорошая реализация, потому что вы перегружаете ** 'push()', а не переопределяете ее. Пользователь, использующий ваш стек, по-прежнему будет использовать «push» с одним параметром. Проверьте перегрузку и переопределение. – RealSkeptic

+0

Я бы выбрал SortedStack ** использовать ** a Stack. Да, вам нужно создать все методы из Stack, но у вас есть доступ ко всему стеку, а также модификация метода push, как вы пожелаете. –

+0

@RealSkeptic, согласованное переопределение лучше, чем перегрузка. Тем более, что я использую все остальные методы из Stack без изменений. Ваш комментарий помог лучше перефразировать мой вопрос. Мой первоначальный вопрос перефразирован: могу ли я получить содержимое стека, не передавая его методу push(). – rcode74

ответ

1

Прежде всего, если вы распространяете java.util.Stack, вы должны указать базовый тип для него. Это неправильно:

public class SortedStack extends Stack {...} 

В этом случае Stack является сырья типа. Необработанные типы должны использоваться только с устаревшим кодом, поскольку вы теряете безопасность типа. Вместо этого, вы должны использовать:

public class SortedStack extends Stack<Node> {...} 

Это автоматически сделает ваш стек принимать только Node элементы.

Как я уже сказал в комментариях, вы должны быть , переопределяя метод push, не перегружая его. Это означает, что он должен иметь точно такие же параметры, как метод родительского класса push. Таким образом, он должен принимать только параметр Node, и все. Отметьте метод аннотацией @Override, чтобы убедиться, что вы действительно переопределяете его, а не перегружаете. Компилятор выдаст ошибку, если у вас есть дополнительные параметры или несовместимые типы параметров.

Вы заметите, как только вы сделаете это, что вы должны изменить объявление метода также вернуть Node, так как это, как push объявлен в java.util.Stack.

Таким образом, ваш метод должен быть:

@Override 
public Node push(Node n) { 
    ... 
} 

И вы должны вызвать его из main с помощью:

stack.push(new Node(10, 1.1f)); 

Так как вы заявили правильно его с типом, вам не нужно будет отбрасывать результат pop к Node:

node = stack.pop(); // No need for (Node) 

Теперь, когда у нас есть правильно типизированный класс, ну, ваш товар is Стек. Это то, что наследование на самом деле означает: «Этот класс, который я пишу сейчас, это Stack и имеет все методы Stack и хранит все данные Stack, я просто меняю свое поведение».

Таким образом, для доступа к «основному» стекю просто нужно получить доступ к себе. Например, в то время как цикл должен быть:

while (!this.empty()) { 
     if (this.peek().getKey() > n.getKey()) { 
      tempStack.push(this.pop()); 
     } 
     else { 
      break; 
     } 
    } 

И действительно, вы можете также избавиться от this, потому что нет никакой двусмысленности. Вызов empty() совпадает с вызовом this.empty() (вы использовали isEmpty() в своем коде, но java.util.Stack имеет только empty()).

Так что на самом деле должны быть:

while (!empty() && peek().getKey() > n.getKey()) { 
     tempStack.push(pop()); 
    } 

(я улучшил ваш цикл немного, не было никакой необходимости в дополнительных if).

Однако остерегайтесь использовать this.push() или просто push(), чтобы получить свой основной стек. Вместо этого вы можете использовать super.push(). Таким образом, он будет использовать оригинальное поведение push элемента в реальный стек:

super.push(n); // Don't use new Node() here. Push the node you were given. 

    while (!tempStack.empty()) { 
     super.push(tempStack.pop()); 
    } 

Если вы не сделаете это, вы будете называть тот же push вы пишете прямо сейчас рекурсивно. Это не то, что вы хотели - вы хотели, чтобы «обычный» толчок использовался внутри.

Не забудьте вернуть Node, который вы вставили после завершения.

Другим вариантом является не расширение Stack, а повторная реализация всех методов и наличие внутреннего стека. Посмотрите «Композиция против наследования», чтобы решить, что лучше.

+0

Благодарим вас за отличный ответ. На мой взгляд, я думал, что использование этого «везде» в SortedStack будет ссылаться на объект типа Node, а не на сам стек. Ваше подробное объяснение охватывало все вопросы, которые у меня были и на самом деле ожидали каких-либо дальнейших вопросов, которые у меня были бы. Вы упомянули композицию против наследования. Я обязательно посмотрю его и узнаю о относительных плюсах и минусах. В моей первоначальной реализации мой SortedSort не расширил Stack, а использовал внутренний стек. Я чувствовал, что использование наследства будет для меня опытом обучения, и это, безусловно, было! – rcode74

-1

Это единственный способ сделать это. Вы не можете получить доступ к прямым данным, поскольку он хранится в узле как частный, который затем отправляется в Stack

Смежные вопросы