JavaFX runtime main method - java

The Hello World-Tutorial of JavaFX says:
The main() method is not required for JavaFX applications when the JAR file for the application is created with the JavaFX Packager tool, which embeds the JavaFX Launcher in the JAR file. However, it is useful to include the main() method so you can run JAR files that were created without the JavaFX Launcher, such as when using an IDE in which the JavaFX tools are not fully integrated. Also, Swing applications that embed JavaFX code require the main() method.
I tried this and its true, I can start my application without a main method.
However when I declare a main method an call launch from the Application class, the program still works.
The documentation of Application says, that the JavaFX runtime is creating an instance of the Application class and calls the init method.
But how does the JavaFX runtime start? I mean there has to be a main method somewhere, for everything to start. So Iam wondering if I declare a main method by myself, arent there two of them?

I've actually always been interested in how Java launches JavaFX applications, so I decided to debug the process. Some things before the rest of the answer:
I did the debugging with JDK-10 for a standalone desktop application. Some quick glances at the JDK-11 source code suggests the process has not changed between versions.
When I use Application I'm referring to the javafx.application.Application class.
When I use "main method" I'm referring to the public static void main(String[] args) method. Similarly, "main class" refers to the class containing the main method.
All links for source code point to the OpenJDK Mercurial repository.
Virtually all of this is an implementation detail and is subject to change without notice.
Summary
When launching a JavaFX application, if the main class is a subclass of Application then the Java launcher uses it's own, internal main class. This internal class is responsible for initializing the JavaFX toolkit. Once the toolkit is initialized, one of two things can happen.
The Application subclass has a main method.
In this case, some internal JavaFX code invokes the main method. It is now the developers responsibility to finish launching the application via Application.launch.
The Application subclass does not have a main method.
In this case, the same internal JavaFX code launches the application itself. The first case eventually ends up in the same place this case does.
Basically, any main method declared in Application subclasses are not "normal" main methods. Think of this behavior like this:
The internal main method acts as the entry point for the Java application—just like all "normal" main methods
The Application subclass' main method serves as an optional entry point for the JavaFX application, where the JavaFX toolkit is already initialized.
Detailed Answer
First, it is not the case that you "override" the main method of the Application class; the Application class has no main method. What actually happens is that Java uses it's own main class whenever the application's declared main class is a subclass of Application. For posterity, a main class can be declared using one of the following:
Specifying it on the command line (file): java -cp <classpath> foo.Main
Specifying it on the command line (module): java -p <modulepath> -m foo/foo.Main
Specifying it in the JAR manifest: Main-Class: foo.Main
(Another way I'm forgetting?)
The Steps
These steps assume a JavaFX application. Most of this doesn't happen if launching a "regular" Java application.
Step 1: Load the Main Class
An internal class, LauncherHelper, checks and loads the main class via a method named checkAndLoadMain. This method is responsible for resolving the main class based on how the main class was declared (described above). Once found, this method checks whether or not the main class is a subclass of Application. If it is, then the main class is changed to a static inner class: LauncherHelper$FXHelper. Then some validation is performed and the Class is returned to, I assume, native code.
Relevant code:
java.base/sun.launcher.LauncherHelper
java.base/sun.launcher.LauncherHelper.checkAndLoadMain
java.base/sun.launcher.LauncherHelper$FXHelper
Step 2: Invoke the main Method
After the main class has been found, loaded, and validated it is called from (I assume) native code. Since we are talking about a JavaFX application the main class is now LauncherHelper$FXHelper. The main method of this class does one simple thing: Invoke internal JavaFX code via reflection.
Relevant code:
java.base/sun.launcher.LauncherHelper$FXHelper.main
Step 3: JavaFX Pre-Startup
The code invoked by step 2 is inside a class named LauncherImpl; specifically, the launchApplication(String,String,String[]) method. This method appears to do similar things as LauncherHelper.checkAndLoadMain except more specific to JavaFX.
I believe this method is similar to checkAndLoadMain because the checkAndLoadMain method validated the FXHelper class, which is obviously valid. However, launchApplication needs to validate the Application subclass.
Relevant code:
javafx.graphics/com.sun.javafx.application.LauncherImpl
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
Step 4: JavaFX Startup
The next method called is launchApplicationWithArgs(ModuleAccess,String,String,String[]). This method is responsible for starting the JavaFX toolkit. After this, it loads the Application subclass and, if present, Preloader subclass as actual Class instances. It does this on the JavaFX Application Thread but then returns to the main thread.
The code then takes one of two paths depending on the presence of a main method in the Application subclass:
A main method exists: Proceed to step 5.
A main method does not exist: Proceed to step 6 (launch the application directly)
Relevant code:
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs
Step 5: Invoke main Method of Application Subclass (Optional)
If there is a main method in the Application subclass it is invoked via reflection. It is now the responsibility of the developer to continue the launching procedure via a call to Application.launch. There are two overloads of the launch method:
Application.launch(String...)
Application.launch(Class,String)
The only difference being the first option uses the calling Class as the JavaFX Application subclass. Both end up calling LauncherImpl.launchApplication(Class,String[]). This latter method simply loads the Class of the Preloader, if needed, and then continues on to the next step.
Relevant code:
javafx.graphics/javafx.application.Application.launch(String...)
javafx.graphics/javafx.application.Application.launch(Class,String...)
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
Note: Different method than the one linked in step 3.
Step 6: Finish Launching JavaFX Application
Now we're in the LauncherImpl.launchApplication(Class,Class,String[]) method. This method does two simple things:
Create and start the JavaFX-Launcher thread which calls another method
LauncherImpl.launchApplication1(Class,Class,String[])
Park the main thread (or whatever thread called Application.launch) in a CountDownLatch until the JavaFX toolkit exits.
The launchApplication1 method will start the JavaFX toolkit if it hasn't already been started. Then it continues on to implement the standard JavaFX life-cycle. This involves creating the Application and, if present, Preloader classes then calling the init() and start(Stage) methods at the appropriate times on the appropriate threads. This life-cycle is the publicly defined behavior; virtually everything else mentioned here are implementation details.
Relevant code:
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
Note: Again, different method from the ones linked in steps 3 and 5.
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1
Non-Application Main Class
There is another way to launch JavaFX applications where the main class is not a subclass of Application, like so:
// main class
public class Main {
public static void main(String[] args) {
Application.launch(App.class, args);
}
}
// JavaFX Application class
public class App extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
// setup and show primaryStage
}
}
Since Main is not a subclass of Application the change to FXHelper, in step 1, doesn't take place. This also means that steps 2-5 don't happen automatically. Instead, the call to Application.launch in Main starts this process at the final step: 6. That's why the the launchApplication1 method also tries to start the JavaFX toolkit since it wouldn't have been started in this scenario.

One possible answer would probably be, that there is a main method declared in Application. And if another class, which extends from Application, has its own main method, the code would still be valid and the main method of Application will be ignored::
class Main extends OtherMain {
public Main(String text) {
System.out.println(text);
}
/* If this method is removed, the main-method is called from OtherMain */
public static void main(String[] args) {
new Main("Called from Main-Class");
}
}
class OtherMain {
public static void main(String[] args) {
new Main("Called from Other-Main-Class");
}
}
Does this make sense?

Related

Why do java programs start with a class definition?

It is said that a java program itself is a class, but I just don't get the logic behind this.
The java program itself starts of by the definition of a class (after importing the packages...etc) and the main method itself is defined inside a class.
Why is it this way?
Why does a main method have to be included within a class rather than outside as a separate method/function like in the languages such as c, c++...etc.
For example a simple hello world program in java:-
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello world!"+"Hello again");
}
}
Why is it necessary that a program should start with a class and the main method included within it?
The JVM doesn't understand the concept methods outside of a class. Fundamentally any method called by the JVM will have to be in a class. The main method is static as at the start of a java application nothing will have been initialised, so making it static allows the JVM to call it as a starting point.
Because the Java language specification says so! See here for example. Or more precisely:
The Java Virtual Machine starts up by loading a specified class and then invoking the method main in this specified class.
(to be found right in the beginning of chapter 12, Execution).
Sometimes there isn't a "big" reason behind things.The fathers of the java language probably had a look around what other languages did at that time when they started Java. They decided to go for this approach - and there was never a hard, pressing reason to come back and change that.
Beyond that: you have to understand that the JVM doesn't care about Java source code. It only cares about the Java bytecode specification - and complete classes coming in as compiled .class files.
In other words: there is simply no other "unit" that could wrap around single methods/functions but classes.
The Java Virtual Machine (JVM) has to start the application somewhere. As Java does not have a concept of “things outside of a class” the method that is called by the JVM has to be in a class. And because it is static, no instance of that class is created yet.

In java, do I always need a Main class?

I know that I'll need a main method, but can that main method be in a different class other than the Main class?
Not all Java applications require a main method.
Java can also be used to create web applications, for instance, which don't require main methods to run.
The answer to your question depends on what exactly you mean. Do you mean a class with the name 'Main'? Then, no, there is no requirement for this at all.
The only requirement that Java has, is that the signature of the method is correct. the main method must:
be public
be main
be static
have returntype void
accept an array of Strings as (only) parameter
It's easier to add it in the public class in a file, but not mandatory. The name of the class it is in, is entirely up to you, though many will choose a name like 'Main' or 'Open', simply to more easily find it.
If you want to be able to run your application, by simple double-clicking the .jar file, you'll need to point to the class that contains the main method (to use: your application might contain a lot of main classes, used for internal testing, but only one can be used to start the actual application) in the manifest file: Manifest files
Prior to Java 7, it was possible to run a desktop application without a main method, by (ab)using an instantiation block, but this was removed as of Java 7, because this is not what the instantiation block was intended for.
It's not necessary to define yout main method in a main class. You can place your main method wherever you want, as long the syntax i correct :
public static void main (String[] args){
//...
}
You absolutely don't.
The method itself can be placed whereever you want it to be, there is no limitation.
However, I personally would recommend putting it in a class which at least contains something like "Main", because when others look at your code, and they are not using an IDE which supports jumping to the main method, people usually have an easier time finding your starting point.
However, that is just for sake of readability, and as I said, jumping to main is/should be usually a widespread supported feature
Yes, the Main method is required to run a function although a java class can be without the Main method. Though, it won't run...

Generally what is put in the main method and what isn't? - java

Beginner just starting out
.can i write entirety of code outside of main and still run? generally i'm asking what is "main" used for?
In theory you can just code everything in main and in will work. However to make your code structured you probably want to code outside of main and call it from main.
The main Method is the start point for the VM of Java. So if you want to run your application, there has to be a main method. Not only Java has this concept, also other OOP-Programminglanguages like C,C++,C#. You can write code outside the main. but remember that the code can only be accessed if there is a way to it from the main Method, example functions.
The main method is where your system is able to call and start the program up. The main method is needed if you wish to run your program and make use of your other classes.
You can create your program inside the main method if you wish, but as your programs become more sophisticated, you are going to want to create other classes that are initialized and used in your main method.
For example, if you make two classes called "Suv" "Sedan", and make one more class called "Mechanic" - the class that will hold your main - you can initialize Suv and Sedan and you can call the methods you made in Suv and Sedan to do things like change the engine, or to change the color, etc.
If you are just learning java, then don't worry about it too much and just write your code in your main method.
Main is the entry point of any java application. The Java Virtual Machine starts up by loading a specified class and then invoking the method main in this specified class.
You can write your code in main method, or somewhere else and call that in the main method in the order in which you want to execute it.
The method main must be declared public, static, and void. Following is the reason for it:
public:- main is marked public so that it can be accessed from anywhere outside the scope of the class or broadly we can say outside the scope of project.
static:- It is marked static so that it can be called without any instance of the class. Without declaring main method static, your program will compile successfully but throw an error at run time.
void:- The keyword void is used with main to tell the JVM that the main method does not return any value. It is solely for the initiation of the application not for returning anything.
Following is the valid declaration of the main method:
public static void main(String[] args)
public static void main(String... args)

Passing Parameters in JavaFx

I have implemented a GUI using javafx in a class called "Gui" which extends apllication. I have a seperate class which handles the logic called "Logic". I want to pass an instance of "Logic" class to to "Gui" class. Is there anyway that I can create an instance of "Gui" class before calling "Application.launch()" in main method?
Not easily, and this is almost always the wrong way to approach this. In particular, you don't even know that the main(...) method will be invoked: in Java 8 a JavaFX application is launched by the JVM without (necessarily) calling main(...) at all.
You should really consider the start(...) method in your Application subclass as the equivalent of the main(...) method in a regular Java application; in other words, think of this as your application entry point and create the Logic instance there.

Why JavaFX Application.launch() takes class as an argument?

I'm new to javaFx and looked a bit into source code and have a question regarding
Application.launch function that is used to start an app.
Signature looks like this:
public static void launch(Class<? extends Application> appClass, String... args)
And my question is why it doesn't look like this:
public static void launch(Application app, String... args)
What authors try to achieve by taking class as an argument?
Because an instantiation of the Application is a complex task which FX developers have to have the control over.
The Application instantiation:
requires "FX toolkit" to be initialized in advance
differs for the desktop, jnlp and plugin modes
requires the specific timing
should be called on the special "launcher" thread
should trigger the application lifecycle events
should read the application parameters (from CLI or jnlp file)
Thus you provide only class name to launch and JavaFX do all the work required, including creating an object for you.
I think one of the reason is that this way it more works like it would when you could launch directly through "java my.pkg.MyApp" which you can now in Java8/FX8 because it is on the classpath.
For a definitive answer you'd probably have to ask at the openjfx-mailing list.
The class argument denotes the immediately enclosing class of the method that called launch
Probably, they are using Reflection under the hood. Something like, get the name of the class as an argument to launch() then call the start() of that class.
As with other questions on Stack where people ask what the authors were trying to achieve, we are not privy to the decisions they make.

Categories

Resources