2

I want to make my superclass an abstract class, however I am getting various exceptions when trying to do so (InstantiationException, RuntimeException, InvocationTargetException). My code works when I do not have my superclass as abstract. How do I fix this?

I have tried including my "main" and "start" functions outside of the abstract class body as I believed it may have been an issue calling these functions inside an abstract class. I moved these methods into a subclass which extends the abstract class. Then I overrode the abstract method "start" in each subclass. This reformatting did not solve anything though as I get the same errors. From what I've researched in this question How do you call a subclass method from a superclass in Java? the format this user uses is close to what I am trying to achieve with my abstract superclass extending "Application."

package tutorial.application;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import java.lang.Math;


public abstract class Test extends Application{

    private int width = 0;
    private int height = 0;

    public Test() {
        this.width = 0;
        this.height = 0;
    }

    public Test(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public abstract void draw(GraphicsContext GC);


    public class MyLine extends Test{

        private int x1, x2, y1, y2;

        public MyLine(int x1, int y1, int x2, int y2) {
            super(0, 0);
            this.x1 = x1;
            this.x2 = x2;
            this.y1 = y1;
            this.y2 = y2;
        }

        @Override
        public void draw(GraphicsContext GC){
            GC.strokeLine(x1, y1, x2, y2);
        }
    }

    public static void main(String []args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        int canvasx = 400, canvasy = 650;
        MyLine line = new MyLine(0, 0, canvasx, canvasy);
        MyLine line2 = new MyLine(0, canvasy, canvasx, 0);
        Group root = new Group();
        Canvas canvas = new Canvas(canvasx, canvasy);
        GraphicsContext GC = canvas.getGraphicsContext2D();
        line.draw(GC);
        line2.draw(GC);
        root.getChildren().add(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}

When I don't have my superclass as an abstract class and draw is no longer an abstract method, I get this which is my desired output: https://i.stack.imgur.com/Y2tVt.png

However, otherwise I am getting the following error messages:

Exception in Application constructor
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Unable to construct Application instance: class tutorial.application.Test
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:890)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: java.lang.InstantiationException
    at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:802)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    ... 1 more
Exception running application tutorial.application.Test

Edit: I have so far tried about 3 significantly different options all resulting with errors. Firstly I tried making the subclass static from within the hierarchy as follows:

static class MyLine extends Test{
.
.
.
}

I have also tried again to take the inner class "MyLine" out of the superclass "Test" as follows:

public abstract class Test extends Application{

    private int width = 0;
    private int height = 0;

    public Test() {
        this.width = 0;
        this.height = 0;
    }

    public Test(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public abstract void draw(GraphicsContext GC);

    public static void main(String []args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        int canvasx = 400, canvasy = 650;
        MyLine line = new MyLine(0, 0, canvasx, canvasy);
        MyLine line2 = new MyLine(0, canvasy, canvasx, 0);
        Group root = new Group();
        Canvas canvas = new Canvas(canvasx, canvasy);
        GraphicsContext GC = canvas.getGraphicsContext2D();
        line.draw(GC);
        line2.draw(GC);
        root.getChildren().add(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
}

class MyLine extends Test{

    private int x1, x2, y1, y2;

    public MyLine(int x1, int y1, int x2, int y2) {
        super(0, 0);
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
    }

    @Override
    public void draw(GraphicsContext GC){
        GC.strokeLine(x1, y1, x2, y2);
    }
}

Laslty I designed a new class "Main" to extend "Test" and launching the application from there as follows:

package tutorial.application;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import java.lang.Math;


public abstract class Test extends Application{

    private int width = 0;
    private int height = 0;

    public Test() {
        this.width = 0;
        this.height = 0;
    }

    public Test(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public abstract void draw(GraphicsContext GC);


}

class MyLine extends Test{

    private int x1, x2, y1, y2;

    public MyLine(int x1, int y1, int x2, int y2) {
        super(0, 0);
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
    }

    @Override
    public void draw(GraphicsContext GC){
        GC.strokeLine(x1, y1, x2, y2);
    }

    @Override
    public void start(Stage arg0) throws Exception {

    }
}

class Main extends Test{
    private Main() {
        super(0,0);
    }
    public static void main(String []args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        int canvasx = 400, canvasy = 650;
        MyLine line = new MyLine(0, 0, canvasx, canvasy);
        MyLine line2 = new MyLine(0, canvasy, canvasx, 0);
        Group root = new Group();
        Canvas canvas = new Canvas(canvasx, canvasy);
        GraphicsContext GC = canvas.getGraphicsContext2D();
        line.draw(GC);
        line2.draw(GC);
        root.getChildren().add(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    @Override
    public void draw(GraphicsContext GC) {

    }
}

The first two still result in the same errors and the last one I believe worsens my problem as it throws a new exception in thread "main":

Exception in thread "main" java.lang.reflect.InvocationTargetException
zehFlowr
  • 21
  • 2
  • 1
    If you read the _javadoc_ for `InstantiationException` you will see that abstract classes cannot be instantiated via reflection. If you study the stack trace you posted, you will see that the code is trying to instantiate your `Test` class via reflection. – Abra Oct 25 '19 at 05:21
  • 1
    `launch` always starts the class containing the method calling `launch` (or similar) and that's the `Test` class. You could specify a diffent class as additional parameter to the `Launch` method. Note that `MyLine` won't work either, since it's a non-`static` inner class and therefore would require a parameter of the containing class to construct. (A constructor being able to be reflectively called passing no parameters is required.) – fabian Oct 25 '19 at 05:48

2 Answers2

2

The reason you can’t instantiate the subclass if the superclass is abstract is that the subclass is an inner class of the superclass and to instantiate an inner class you need an instance of the containing class, but by definition you cannot instantiate an abstract class.

Make the subclass static and your problem should be fixed.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

I found a working solution by renaming my class file to be named "Main." This allowed me to keep the abstract class "Test" and all of it's sublclasses and I launched the Application through my new public class "Main" which extends "Application."

zehFlowr
  • 21
  • 2