2

I've looked around here find an answer to my question and I can't. How do you call a subclass method from a superclass in Java?

Basically what I'm looking to do is this: I have a method called exec that takes a String as a parameter for a command. I want to be able to call the exec method in the subclass that the developer has overridden from the superclass without knowing the subclasses name ahead of time.

This is like the way the Thread class works. I'm not looking to do what every answer I've found does which is Superclass object = new Subclass(); and then just call object.method();.

This is the code in the superclass

import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.scene.text.Text;



public abstract class Console extends Application {
    private String title;
    private static Text output = new Text();


    public void create(String title) {
        this.title = title;
        launch();
    }

    public void start(Stage stage) {
        stage.setOnCloseRequest((WindowEvent event) -> {
            System.exit(0);
        });
        stage.setTitle(title);
        stage.setResizable(false);
        Group root = new Group();
        Scene scene = new Scene(root, 800, 400);
        stage.setScene(scene);
        ScrollPane scroll = new ScrollPane();
        scroll.setContent(output);
        scroll.setMaxWidth(800);
        scroll.setMaxHeight(360);
        TextField input = new TextField();
        input.setLayoutX(0);
        input.setLayoutY(380);
        input.setPrefWidth(800);
        scene.setOnKeyPressed((KeyEvent event) -> {
            if(event.getCode() == KeyCode.ENTER) {
                exec(input.getText());
                input.clear();
            }
        });
        root.getChildren().add(scroll);
        root.getChildren().add(input);
        stage.show();
    }
    public static void appendOutput(String value) {
         Platform.runLater(() -> {
            output.setText(output.getText() + "\n" + value);
        });
    }
    protected abstract void exec(String command);
}
Scoopta
  • 987
  • 1
  • 9
  • 22
  • 2
    Simple answer: you can't ... do you have code to show? – Caffeinated Jan 19 '15 at 19:51
  • 6
    You don't. Superclass should not know anything about its subclasses. – Rafal G. Jan 19 '15 at 19:51
  • 2
    You shouldn't - that's what inheritance is for. – Nir Alfasi Jan 19 '15 at 19:51
  • 2
    @R4J: Nonsense. Superclasses know lots about their subclasses, and can know that subclasses will have a particular method by defining a contract; i.e. declaring the method in the parent (often as abstract). – Mark Peters Jan 19 '15 at 19:53
  • 1
    @Mark Peters that actually might be the answer I'm looking for. – Scoopta Jan 19 '15 at 19:56
  • 1
    @MarkPeters right, I kinda assumed that OP askes about calling non-inherited method defined only in a subclass. My bad :/ – Rafal G. Jan 19 '15 at 19:57
  • @Scoopta: This is just the default behavior of methods as answered by aioobe. Maybe you could say where you're running into trouble? Also see this tutorial: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html – Mark Peters Jan 19 '15 at 19:57
  • @MarkPeters alright. This is what I'm doing. I have a javafx class in a different package that I want to use as a library. I have a key listener so that when the user presses enter it takes the data in a text box and passes it into the exec method. I want it to run the overridden exec method in place of the one in the superclass so that it execs the subclasses code. – Scoopta Jan 19 '15 at 20:04

3 Answers3

4

[...] I have a method called exec that takes a String as a parameter for a command. I want to be able to call the exec method in the subclass that the developer has overridden from the superclass without knowing the subclasses name ahead of time.

You don't have to do anything special. You just call it from the code of the base class. All methods in Java are virtual, so the overriding implementation of the subclass will be invoked.

Here's a demo:

public class Test {
    public static void main(String[] args) {
        Console console = new ConsoleSubclass();
        console.start();
        console.keyPressed();
    }
}

abstract class Console {

    Runnable keyPressedHandler;

    private void setOnKeyPressed(Runnable handler) {
        keyPressedHandler = handler;
    }

    public void keyPressed() {
        keyPressedHandler.run();
    }

    public void start() {
        setOnKeyPressed(() -> {
            exec();
        });
    }

    abstract void exec();
}

class ConsoleSubclass extends Console {
    @Override
    void exec() {
        System.out.println("In ConsoleSubclass");
    }
}
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • What do you mean by base class? – Scoopta Jan 19 '15 at 20:01
  • The answer is a bit misleading. You don't have to "call it from the base class.". If method x() is defined in the superclass, and overridden in the subclass, then any class that has a reference to an object of the subclass can call objectReference.x(), and that calls the method in the subclass. This is true even if the type of the declaration for that reference is the type of the superclass. – arcy Jan 19 '15 at 20:12
  • Updated the answer slightly. Not sure I get what you mean though. In the OPs case, he want's to call the subclass implementation from the superclass. – aioobe Jan 19 '15 at 20:30
  • @Scoopta, base class is synonym to super class. – aioobe Jan 19 '15 at 20:39
  • Yea...that would work I only have one problem left. If you look at the code in my original question. I'm looking to have it execute the exec method when the user presses enter. The problem is that the call exists soley within the superclass and is called via an EventHandler – Scoopta Jan 19 '15 at 23:36
  • This should not be a problem as long as the handler does not define an exec method. – aioobe Jan 20 '15 at 06:18
  • @aioobe but how would I go about doing it? I have a `create(String title)` method that is responsible for invoking the launch method to start the javafx thread but if I do: `new SubClass().create("title");` I get a java.lang.reflect.InvocationTargetException in the constructor and if I change `create(String title)` to static and reference it that way then it won't call exec in the SubClass but rather it'll call exec in the SuperClass. – Scoopta Jan 20 '15 at 09:04
  • I'm very surprised that you get java.lang.reflect.InvocationTargetException. Could you elaborate on how you do to get this? (I don't see any create-method in your post.) Also, it is correct that static methods can't be overridden, so making it static will not, as you've discovered, work. – aioobe Jan 20 '15 at 09:08
  • @aioobe I'll post the entire class in my post. I only posted what was relavent but I should have just posted everything. – Scoopta Jan 20 '15 at 22:35
  • I've updated my demo snippet to show that it should indeed work. If you still can't make your code work, please modify the snippet I posted to demonstrate what goes wrong. – aioobe Jan 22 '15 at 08:30
  • @aioobe This brings me to another problem...I have no clue how to make a JavaFX application without extending Application and I've been looking everywhere but it's not something that's commonly done. I don't even actually know if it can be done. You're example neglects the JavaFX code and without the JavaFX code I have no problem but I also have no application. I know how to subclass normally but my issue is doing it with JavaFX – Scoopta Jan 23 '15 at 02:28
  • What JavaFX code does it neglect? If the Application class plays a central role in the problem you need to clarify that in the question. As it stands I think my answer covers your question quite well. – aioobe Jan 23 '15 at 10:46
  • @aioobe for a JavaFX program you have to extend `Application` and have a method `public void start(Stage stage) {}`. To start the JavaFX thread you make a call to `launch();`. Your code does none of that and then your key listener isn't JavaFX either. All I'm getting at is that your example removes all of the JavaFX components from the code and makes a direct call to `start();`. It's so different from my own code I'm not sure what to do with it. – Scoopta Jan 24 '15 at 07:05
  • I understand, but please show how those classes and methods come inte play. Please provide some sort of minimal example that demonstrates the issue. – aioobe Jan 24 '15 at 07:39
  • @aioobe I'm not sure how to put together an example but basically the issue is that JavaFX seems incredibly finicky about the type of classes that can be used for an application. They cannot be abstract or you get that constructor error. They cannot contain a constructor that interacts with the JavaFX application or you get the error. You also can't invoke a method in them like my `create(String title);` method by doing `new Subclass().create("title");`. It seems that that won't work even though if I don't extend SuperClass and then I call the method statically or through an object it works. – Scoopta Jan 28 '15 at 05:09
  • Your first issues are JavaFX issues. How `new Subclass().create("title")` should work is fundamental Java semantics and I honestly doubt JavaFX don't adhere to this. It seems like your issue was slightly different from what you originally asked. I suggest you accept this answer, and post a follow up question that includes what your last comment said and tag it with JavaFX. – aioobe Jan 28 '15 at 08:36
  • @aioobe alright you're probably right so I'll do that. I get what you're saying but I'm saying if I do that I get an error haha... – Scoopta Jan 28 '15 at 23:11
  • Seems your issue was resolved in your follow up question! :-) Make sure to accept one of the answers in this thread so we get a closure here as well. – aioobe Jan 31 '15 at 14:40
0
public class UsingClass

{
  SuperClassType x = null;
  x = goGetClassReference(); // this can get an instance of SuperClassType,
                             // or of any subclass of it.
  x.methodName();  // this calls methodName on the class obtained above; 
        //if goGetClassReference got a subclass, this calls methodName() on the subclass.
}
arcy
  • 12,845
  • 12
  • 58
  • 103
0

The answer for my specific JavaFX subclassing question is over here Subclassing a JavaFX Application. For general subclassing the answers here are quite adequate.

Community
  • 1
  • 1
Scoopta
  • 987
  • 1
  • 9
  • 22