[Caveat: I am not an expert on JavaFX. I may well be wrong on some points.]
tl;dr
The abstract javafx.application.Application
class is not being instantiated. As you correctly note, instantiating an abstract class would violate the Java language specification.
The JavaFX framework uses the magic of reflection to instantiate an object of a concrete class, your subclass of Application
.
The non-static methods init
, start
, and stop
defined by Application
are being implemented by your subclass of Application
. It is those implementations you write on your concrete subclass that are being executed by the JavaFX framework.
So concrete methods on an object of a concrete class, no abstract
involved.
Lifecycle
Let's review the lifecycle of a modern JavaFX/OpenJFX app.
main
When any kind of Java app launches, the JVM executes the designated main
method in a thread dedicated to that app.
launch
In a JavaFX app, that main
method should be written to call either of the two overloaded static
methods javafx.application.Application.launch
. The class containing this main
method must either (a) extend from javafx.application.Application
, or (b) the call to launch
must pass the Class
object of your class that does extend from Application
.
The launch
method is only called once per life of your app. And the launch
method does not return until the end of the app’s life.
Something like this:
public class TimeApplication extends Application
{
public static void main ( String[] args )
{
javafx.application.Application.launch ();
}
}
init
Immediately after loading and constructing the Application
class via your subclass, the Application#init
method is automatically called. This call happens on a background thread, as seen in my example code below. This background thread is not the original app thread, and is not the JavaFX Application Thread discussed below.
The default implementation of that method does nothing. You may choose to provide an implementation that overrides this method. That override is your hook to perform initialization crucial to your app before any of the GUI has been established.
You may want to use the init
override to establish necessary resources, and verify the operating environment. For example, you may want to verify that expected external services are indeed available such as user authenticators, web services, message queues, and database servers. Your init
method might spin off threads to prepare information later needed by your user.
But you cannot construct a Stage
or Scene
in init
as the JavaFX display framework has not yet been established. You may construct other JavaFX objects. You set the Scene
& Stage
and their contents in the start
method running on a separate thread.
Simple example:
public class TimeApplication extends Application
{
@Override
public void init ( ) throws Exception // On original app thread.
{
if ( ! userAuthServiceIsAvailable ( ) )
{
// … handle failure …
}
}
public static void main ( String[] args ) // On original app thread.
{
Application.launch ( );
}
}
start
After the init
method (either your override or the default no-op) completes its execution, then Application#start
is automatically called. The JavaFX framework automatically constructs and passes a Stage
object representing the initial window of your app.
To quote the Javadoc:
The main entry point for all JavaFX applications. The start
method is called after the init
method has returned, and after the system is ready for the application to begin running.
The Application#start
method is the place to establish the initial GUI for your app. You construct a Scene
object, and assign it to the passed Stage
object.
This method executes on a new thread established for JavaFX GUI event handling. This thread is known in the Javadoc as JavaFX Application Thread.
Note that start
is marked abstract
, which means the Application
class does not contain an implementation of this method. This means your subclass of Application
must contain an implementation for this method — if omitted your app would not compile. Note the contrast to init
and stop
methods which are not abstract
and have an implementation in Application
(an implementation that happens to do nothing, but an implementation nevertheless). So writing an override for init
& stop
is optional for us, but writing a start
method is required.
stop
The counterpart to Application#start
is Application#stop
. The method is automatically called by the JavaFX framework when the app is going to quit/exit.
The default implementation does nothing. You may choose to override this method as a hook for you to close resources and perform other clean-up chores appropriate to the app ending.
This method executes on the JavaFX Application Thread.
Example code
package work.basil.example;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.time.Instant;
public class TimeApplication extends Application
{
@Override
public void init ( ) throws Exception
{
System.out.println ( "The init method is running on thread " + Thread.currentThread ( ).threadId ( ) + " “" + Thread.currentThread ( ).getName ( ) + "”" + " at " + Instant.now ( ) );
if ( ! this.userAuthServiceIsAvailable ( ) )
{ /* … handle failure … */ }
}
@Override
public void start ( Stage stage )
{
System.out.println ( "The start method is running on thread " + Thread.currentThread ( ).threadId ( ) + " “" + Thread.currentThread ( ).getName ( ) + "”" + " at " + Instant.now ( ) );
// Scene
Button button = new Button ( );
button.setText ( "Tell time" );
button.setOnAction ( ( event ) -> System.out.println ( Instant.now ( ) ) );
VBox vbox = new VBox ( button );
Scene scene = new Scene ( vbox );
// Stage
stage.setTitle ( "Time keeps on slipping, slipping, slipping" );
stage.setHeight ( 300 );
stage.setWidth ( 500 );
stage.setScene ( scene );
stage.show ( );
}
@Override
public void stop ( ) throws Exception
{
System.out.println ( "The stop method is running on thread " + Thread.currentThread ( ).threadId ( ) + " “" + Thread.currentThread ( ).getName ( ) + "”" + " at " + Instant.now ( ) );
}
private boolean userAuthServiceIsAvailable ( )
{
return true;
}
public static void main ( String[] args )
{
System.out.println ( "The main method is beginning on thread " + Thread.currentThread ( ).threadId ( ) + " “" + Thread.currentThread ( ).getName ( ) + "”" + " at " + Instant.now ( ) );
Application.launch ( );
System.out.println ( "The main method is ending on thread " + Thread.currentThread ( ).threadId ( ) + " “" + Thread.currentThread ( ).getName ( ) + "”" + " at " + Instant.now ( ) );
}
}
Be aware that output to System.out
does not necessarily appear in chronological order when called across threads. Include timestamps, and study them, to verify sequence of actions.
Example output:
The main method is beginning on thread 1 “main” at 2023-07-31T19:57:37.255140Z
The init method is running on thread 27 “JavaFX-Launcher” at 2023-07-31T19:57:37.262522Z
The start method is running on thread 24 “JavaFX Application Thread” at 2023-07-31T19:57:37.268091Z
2023-07-31T19:57:39.206604Z
2023-07-31T19:57:39.391998Z
2023-07-31T19:57:39.524548Z
The stop method is running on thread 24 “JavaFX Application Thread” at 2023-07-31T19:57:42.402692Z
The main method is ending on thread 1 “main” at 2023-07-31T19:57:42.404950Z
Summary of lifecycle
Here is my table of lifecycle activities. Note that init
and start
run at the same time, not sequentially, running on separate threads.
Sequence step # 3 is when the JavaFX framework uses reflection to instantiate an object of your subclass of Application
.
Your questions
in javaFX Application is an abstract class.
Yes. Being abstract means you are intended to write a subclass of Application
. Thus we have TimeApplication extends Application
in code above.
some abstract methods which are overridden in main class which extends abstract Application class and also have static launch() method
Yes, both launch
methods are static
. So we call them with syntax like this: Application.launch()
. No reference to an object.
We usually make the static
call Application.launch()
from the static
method main
. So we have a static
call within another static
call — no objects involved.
The launch() method calls from the main method in main class.
Be aware that the main
method may or may not be housed within the class inheriting from Application
.
The JavaFX framework examines the class containing the Application.launch
call. If that class extends the abstract
class Application
, then you can use the launch
method with only a single argument, args
. If you have an arrangement where the call to Application.launch
takes place in some class that is not a subclass of Application
, then you must use the other launch
method where you pass a Class
object that represents the class that is a subclass of Application
.
What may be confusing you is the lack of a reference to an object of your subclass of Application
. In our example code above, at no point do we see an instantiation like this:
TimeApplication timeApp = new TimeApplication() ;
The reason we see no such instantiation is because of some “magic” in JavaFX. The JavaFX framework is using reflection to instantiate our subclass on our behalf.
The construction of our subclass happens behind the scenes, with no reference in our sight. At no point do we get back a reference to the object of our subclass. See discussion on the Question Getting application instance in javafx. If you really want a reference to the object of your subclass of Application
, see the workaround in this Answer.
Now how is it possible launch() method calls these abstract methods and for these calls overridden methods in main class are executes?
The static
call to Application.launch
results in the concrete subclass (TimeApplication
in our example) inheriting from the abstract Application
class. So we have an object, a TimeApplication
object, in memory, but we do not see any reference to it. That object has the override methods of init
, start
, and stop
. So we have a concrete object, not abstract, with regular overrides methods being executed at various points in time on various threads. The Java rules you mention are being followed properly, as described in these two bullets:
-
I know that non-static method can't invoked from static method
We are not invoking non-static methods from a static context. The non-static init
, start
, and stop
methods are being executed on an object of our concrete subclass TimeApplication
that was automatically instantiated for us, not by us. The calls to those methods init
, start
, and stop
are also being made for us, not by us.
-
and it is not possible to create instance of an abstract class.
You are correct — No instance was made of the abstract class Application
. The JavaFX used the magic of reflection to create, behind the curtains, an instance of our subclass of Application
. Via reflection, JavaFX created an instance of TimeApplication
in our example above. The framework instantiated an object of a concrete subclass extending an abstract class.