Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does JavaFX 8 start the JavaFX Application thread in a nearly empty Application class?

Lets say, we have the following class:

import javafx.application.Application;
import javafx.stage.Stage;

public class Test extends Application
{
    public Test()
    {
        System.out.println("Constructor");
    }

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        System.out.println("start");
    }

    public static void main(String... args)
    {
        System.out.println("main");
    }
}

It's derived from Application but it doesn't use any of its methods. Usually you start a JavaFX application by calling launch(args) in the main.

When I start this program the only output is "main", so the constructor and start aren't called, but the program doesn't terminate because there is a JavaFX Application thread running. But where does it come from?

I did some debugging and found out that the thread is started from the main thread before the main method runs. The stack trace starts with NativeMethodAccessorImpl.

To get even weirder: when I start the main method from a different class, the JavaFX Application thread isn't started:

public class Test2
{
    public static void main(String[] args)
    {
        Test.main(args);
    }
}

So what kind of black magic is this?

like image 541
Mr. Clear Avatar asked Feb 04 '15 12:02

Mr. Clear


Video Answer


1 Answers

Java uses different approaches to launch the two applications.

Try running the following code:

public class Test3 {

    public static void main(String[] args) {

        Class<?> actualMainClassTest = LauncherHelper.checkAndLoadMain(true, 1, Test.class.getName());
        Class<?> actualMainClassTest2 = LauncherHelper.checkAndLoadMain(true, 1, Test2.class.getName());

        System.out.println("Actual loaded main class for Test: " + actualMainClassTest.getName());
        System.out.println("Actual loaded main class for Test2: " + actualMainClassTest2.getName());
    }
}

The output is

  • Actual loaded main class for Test: sun.launcher.LauncherHelper$FXHelper
  • Actual loaded main class for Test2: Test2

You can see that the actual loaded main class for the Test2 class is Test2, but the loaded main class for Test is sun.launcher.LauncherHelper$FXHelper.

This happens because the Java launcher checks if the main class to be launched is a subclass of javafx.application.Application. If it is, it loads the main method of sun.launcher.LauncherHelper$FXHelper instead, which invokes a launcher method for JavaFX applications (com.sun.javafx.application.LauncherImpl#launchApplication).

This method is responsible for launching the JavaFX application. Test#main is called after the application is launched:

enter image description here

When Test#main is called by Test2, the FX launcher is not used because Test2 is not a subclass of javafx.application.Application.

like image 140
Modus Tollens Avatar answered Sep 30 '22 07:09

Modus Tollens