in javaFX Application is an abstract class. In this abstract class there have some abstract methods which are overridden in main class which extends abstract Application class and also have static launch() method in abstract class Application. The launch() method calls from the main method in main class. Now how is it possible launch() method calls these abstract methods and for these calls overridden methods in main class are executes? please help me to understand this procedure actually works. I know that non-static method can't invoked from static method and it is not possible to create instance of an abstract class. abstract method can't be a static method.
I don't want to create object of main class. Because the launch() method don't know what is the name of main class.
Write me a java code where this procedure illustrate well. like this
public class main extends Application{
public static void main(String[] args)
launch(); // launch() was a static method in Application class
}
@override
public void init(){ // init() was an abstract method in Application class
System.out.println("hello");
}
}
public abstract class Application {
public static void launch(){
init();
}
public abstract void init();
}
I want to get output : hello
The Application#launch(String...)
method is defined to:
Launch a standalone application. This method is typically called from the
main
method. [...]. This is equivalent tolaunch(TheClass.class, args)
whereTheClass
is the immediately enclosing class of the method that called launch.
So, it does know the name of the main class by getting the "caller class". It then creates an instance of the application class via reflection and invokes the init()
and start(Stage)
methods as appropriate.
The instantiation of the Application
implementation1 and the invoking of init()
, start(Stage)
, and stop()
, are all part of the JavaFX life-cycle (documented by Application
). You don't instantiate the application class, nor do you call those methods. It's handled by JavaFX.
Note you should not have your own Application
class. Not only is it confusing to name a class the same as a class from the framework you're using, but it does nothing for you. You need to extend javafx.application.Application
if you want the normal JavaFX life-cycle.
1. It's not the Application
class itself that's instantiated, as it's abstract. However, you must provide a concrete subclass (i.e., implementation) as part of your project, and it's that class that's instantiated. Of course, from the point of view of JavaFX, it only knows it has an instance of Application
. But that is basic polymorphism at work.
Here's some non-JavaFX code demonstrating the process. Note it's vastly simplified and does things slightly differently from the actual JavaFX implementation.
package com.example;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class Application {
private static final AtomicBoolean LAUNCHED = new AtomicBoolean();
private static Throwable error;
public static void launch(Class<? extends Application> appClass, String... args) {
Objects.requireNonNull(appClass);
Objects.requireNonNull(args);
if (!LAUNCHED.compareAndSet(false, true)) {
throw new IllegalStateException("already launched");
}
CountDownLatch startLatch = new CountDownLatch(1);
Thread eventThread = new Thread(() -> {
try {
Application instance = appClass.getConstructor().newInstance();
instance.start(args);
} catch (Throwable error) {
Application.error = error;
} finally {
startLatch.countDown();
}
});
eventThread.setName("Application Event Thread");
eventThread.start();
try {
startLatch.await();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
if (error != null) {
throw new RuntimeException("Exception in Application start method", error);
}
}
@SuppressWarnings("unchecked")
public static void launch(String... args) {
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Class<?> callerClass = walker.getCallerClass();
if (!Application.class.isAssignableFrom(callerClass)) {
throw new IllegalStateException("caller class is not a subclass of com.example.Application");
}
launch((Class<? extends Application>) callerClass, args);
}
public abstract void start(String[] args);
}
Then some other code can do:
package com.example;
import java.util.Arrays;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(String[] args) {
System.out.println("Started! args = " + Arrays.toString(args));
}
}
Without having to pass the class to launch
.
As noted, this is vastly simplified from what JavaFX actually does, and it uses some different APIs. For instance:
I used java.lang.StackWalker
(added in Java 9). JavaFX currently (as of 21-ea) still uses code that manually walks the stack trace via Thread.currentThread().getStackTrace()
.
The JavaFX Application Thread is not created manually like I did for the "Application Event Thread" above. Instead, the FX thread is managed by the JavaFX framework, and the real launch code makes use of the internal version of Platform#runLater(Runnable)
.
However, the real JavaFX code does do something similar to what I did for the "JavaFX-Launcher Thread" used to invoke the init()
method.
My code has the "Application Event Thread" instantiate the class, call start(String[])
, and then die (once start
returns). That's not how the JavaFX Application Thread works, which essentially runs in a loop.
The real JavaFX code has to deal with potential Preloader
s.
The real JavaFX code creates a Stage
instance that it passes to the start(Stage)
method; I "simulate" that by passing the given command line arguments array. Though note in a real JavaFX application, if you pass the command line arguments to launch
, then those arguments are encapsulated in a Parameters
object (and rudimentarily parsed).
In the real JavaFX code, the thread that calls launch
is blocked until the framework exits.
If you're truly curious about the entire process, then I recommend you follow the source code.