JavaFX的Hello World-Tutorial说:
使用JavaFX Packager工具创建应用程序的JAR文件时,对于JavaFX应用程序不需要main()方法,该工具将JavaFX Launcher嵌入JAR文件中。但是,包含main()方法非常有用,这样您就可以运行在没有JavaFX Launcher的情况下创建的JAR文件,例如在使用未完全集成JavaFX工具的IDE时。另外,嵌入JavaFX代码的Swing应用程序需要main()方法。
我尝试了这一点,并且确实如此,我无需使用main
方法就可以启动我的应用程序。
但是,当我声明一个main
类的调用launch
的{{1}}方法时,该程序仍然有效。
Application的文档说,JavaFX运行时正在创建Application
类的实例,并调用Application
方法。
但是JavaFX运行时如何启动?我的意思是某处必须有一个init
方法,一切才能开始。因此,我想知道我是否一个人声明了main
方法,是否有两个方法?
答案 0 :(得分:3)
实际上,我一直对Java如何启动JavaFX应用程序很感兴趣,因此我决定调试该过程。其余答案之前的一些事情:
Application
时指的是javafx.application.Application
类。main
方法”时,是指public static void main(String[] args)
方法。同样,“主类”是指包含main
方法的类。启动JavaFX应用程序时,如果主类是Application
的子类,则Java启动器将使用它自己的内部主类。该内部类负责初始化JavaFX工具包。工具箱初始化后,可能会发生以下两种情况之一。
Application
子类具有一种main
方法。
main
方法。现在,开发人员有责任通过Application.launch
完成启动应用程序。Application
子类没有 main
方法。
基本上,main
子类中声明的任何Application
方法都不是“常规” main
方法。考虑这种行为:
main
方法充当Java应用程序的入口点-就像所有“常规” main
方法一样Application
子类的main
方法用作JavaFX应用程序的可选入口点,其中JavaFX工具包已经初始化。首先,不是您“重写”了main
类的Application
方法; Application
类没有main
方法。实际发生的情况是,只要应用程序声明的主类是Application
的子类,Java就会使用它自己的主类。为了后代,可以使用以下任一方法声明主类:
java -cp <classpath> foo.Main
java -p <modulepath> -m foo/foo.Main
Main-Class: foo.Main
这些步骤假定使用JavaFX应用程序。如果启动“常规” Java应用程序,大多数情况不会发生。
内部类LauncherHelper
通过名为checkAndLoadMain
的方法检查并加载主类。此方法负责根据声明主类的方式解析主类(如上所述)。一旦找到,此方法将检查主类是否为Application
的子类。如果是,则主类更改为静态内部类:LauncherHelper$FXHelper
。然后执行一些验证,并将Class
返回到本机代码。
相关代码:
java.base/sun.launcher.LauncherHelper
java.base/sun.launcher.LauncherHelper.checkAndLoadMain
java.base/sun.launcher.LauncherHelper$FXHelper
main
方法在找到,加载并验证了主类之后,从(我假设)本机代码调用它。由于我们正在谈论JavaFX应用程序,因此现在的主要类是LauncherHelper$FXHelper
。此类的main
方法做一件事:通过反射调用内部JavaFX代码。
相关代码:
第2步调用的代码在名为LauncherImpl
的类中;具体来说,是launchApplication(String,String,String[])
方法。除了更特定于JavaFX之外,此方法似乎与LauncherHelper.checkAndLoadMain
类似。
我认为该方法类似于checkAndLoadMain
,因为checkAndLoadMain
方法验证了FXHelper
类,这显然是有效的。但是,launchApplication
需要验证Application
子类。
相关代码:
javafx.graphics/com.sun.javafx.application.LauncherImpl
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
下一个调用的方法是launchApplicationWithArgs(ModuleAccess,String,String,String[])
。此方法负责启动JavaFX工具包。此后,它将加载Application
子类,如果存在,则将Preloader
子类加载为实际的Class
实例。它在 JavaFX Application Thread 上执行此操作,然后返回到主线程。
然后,代码根据main
子类中Application
方法的存在采用两条路径之一:
main
方法:继续执行步骤5。main
方法:继续执行步骤6(直接启动应用程序)相关代码:
main
子类的Application
方法(可选)如果main
子类中有一个Application
方法,则通过反射调用它。开发人员现在有责任通过调用Application.launch
来继续启动过程。 launch
方法有两个重载:
Application.launch(String...)
Application.launch(Class,String)
唯一的区别是第一个选项使用调用Class
作为JavaFX Application
子类。两者最终都呼叫LauncherImpl.launchApplication(Class,String[])
。后一种方法仅在需要时加载Class
中的Preloader
,然后继续进行下一步。
相关代码:
javafx.graphics/javafx.application.Application.launch(String...)
javafx.graphics/javafx.application.Application.launch(Class,String...)
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
现在我们处于LauncherImpl.launchApplication(Class,Class,String[])
方法中。此方法可以完成两件事:
LauncherImpl.launchApplication1(Class,Class,String[])
Application.launch
的任何线程)停放在CountDownLatch
中,直到JavaFX工具包退出。 launchApplication1
方法将启动JavaFX工具箱(如果尚未启动)。然后继续执行标准JavaFX生命周期。这涉及创建Application
和Preloader
类(如果存在),然后在适当的时间在适当的线程上调用init()
和start(Stage)
方法。这个生命周期是公开定义的行为;实际上,这里提到的所有其他内容都是实施细节。
相关代码:
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1
Application
主班还有一种启动JavaFX应用程序的方法,其中主类不是Application
的子类,如下所示:
// 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
}
}
由于Main
不是Application
的子类,因此在步骤1中对FXHelper
的更改不会发生。这也意味着步骤2-5不会自动发生。相反,在最后一步中,在Application.launch
中对Main
的调用将开始此过程:6.这就是launchApplication1
方法也尝试启动JavaFX工具箱的原因,因为它不是在这种情况下开始。
答案 1 :(得分:0)
一个可能的答案可能是,在main
中声明了一个Application
方法。并且,如果从Application
扩展的另一个类具有自己的main
方法,该代码将仍然有效,并且main
的{{1}}方法将被忽略:: < / p>
Application
这有意义吗?