简体   繁体   中英

Java inheritance, how to override a method in subclass

I am working on a practice interview question. The problem is to implement a sorted stack using only one more stack for temporary storage.

Description of implementation: I am extending Stack class to implement my SortedStack class. Most methods of SortedStack class are identical to Stack class, so I don't need to implement them. Only the push method is overridden.

In my implementation, I am passing the current stack to push method. My question is: is this the best way to access the existing stack. Can I access stack's contents without passing it to push() method?

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 is the java.util.Stack as described at: http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html

First thing, if you are extending java.util.Stack , you should provide a base type for it. This is wrong:

public class SortedStack extends Stack {...}

In this case, Stack is a raw type . Raw types should only be used with legacy code, as you lose the type safety. Instead, you should use:

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

Doing so will automatically make your stack accept only Node elements.

As I said in the comments, you should be overriding the push method, not overloading it. This means that it has to have exactly the same parameters as the parent class's push method. Thus, it should only take a Node parameter, and that's it. Mark the method with the @Override annotation to make sure that you are really overriding it and not overloading. The compiler will issue an error if you have extra parameters or incompatible parameter types.

You'll note, once you do that, that you have to change the declaration of the method to also return Node , as this is how push is declared in java.util.Stack .

So your method should be:

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

And you should call it from your main using:

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

Since you have declared it properly with the type, you won't need to cast the result of pop to Node :

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

Now that we have a properly typed class, well, your item is the stack. This is what inheritance actually means: "This class that I am writing now is a Stack and has all the Stack methods, and stores all the Stack data, I'm just changing some of its behavior."

So to access the "main" stack it simply needs to access itself . For example, you while loop should be:

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

And really, you can also get rid of the this because there is no ambiguity. Calling empty() is the same as calling this.empty() (you used isEmpty() in your code but java.util.Stack has only empty() ).

So it really should be:

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

(I improved your loop a bit, there was no need for the extra if ).

However, beware of using this.push() or just push() to get your main stack. You can use super.push() instead. That way it will use the original behavior to push the item into the actual stack:

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

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

If you don't do this, you will be calling the same push you are writing right now recursively. This will not be what you wanted - you wanted a "plain" push to be used internally.

Remember to return the Node you inserted once you are done.

Another option would be to not extend Stack but re-implement all the methods and have an internal stack. Look up "Composition vs. Inheritance" to decide which is better.

This is the only way to do it. You are unable to access direct data, as it is stored in the Node as a private which is then sent to the Stack

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM