gpt4 book ai didi

java - JavaFX运行时主要方法

转载 作者:行者123 更新时间:2023-12-02 13:29:59 27 4
gpt4 key购买 nike

JavaFX的Hello World-Tutorial表示:

当使用JavaFX Packager工具创建应用程序的JAR文件时,对于JavaFX应用程序不需要main()方法,该工具将JavaFX Launcher嵌入JAR文件中。但是,包含main()方法很有用,这样您就可以运行在没有JavaFX Launcher的情况下创建的JAR文件,例如在使用未完全集成JavaFX工具的IDE时。另外,嵌入JavaFX代码的Swing应用程序需要main()方法。

我已经尝试过了,但事实并非如此,我无需main方法就可以启动应用程序。

但是,当我声明main方法以从launch类调用Application时,该程序仍然有效。
Application的文档说,JavaFX运行时正在创建Application类的实例,并调用init方法。

但是JavaFX运行时如何启动?我的意思是某处必须有一个main方法,所有内容才能开始。因此,我想知道是否我自己声明一个main方法,而不是其中两个吗?

最佳答案

实际上,我一直对Java如何启动JavaFX应用程序很感兴趣,因此我决定调试该过程。其余答案之前的一些事项:

  • 我使用JDK-10对独立的桌面应用程序进行了调试。快速浏览一下JDK-11源代码,表明该过程在各个版本之间均未更改。
  • 当我使用Application时,是指javafx.application.Application类。
  • 当我使用“main方法”时,是指public static void main(String[] args)方法。同样,“主类”是指包含main方法的类。
  • 所有源代码链接都指向OpenJDK Mercurial存储库。
  • 实际上,所有这些都是实现细节,如有更改,恕不另行通知。


  • 摘要

    启动JavaFX应用程序时,如果主类是 Application的子类,则Java启动器将使用 自身的内部主类。该内部类负责初始化JavaFX工具包。工具箱初始化后,可能会发生以下两种情况之一。
  • Application子类具有main方法
  • 在这种情况下,一些内部JavaFX代码调用main方法。现在,开发人员有责任通过Application.launch完成启动应用程序。
  • Application子类没有main方法。
  • 在这种情况下,相同的内部JavaFX代码将启动应用程序本身。第一种情况最终以与该情况相同的地方结束。

  • 基本上,在 main子类中声明的任何 Application方法都不是“普通”的 main方法。考虑这种行为:
  • 内部main方法充当Java应用程序的入口点-就像所有“常规” main方法
  • 一样
  • Application子类的main方法用作JavaFX应用程序的可选入口点,在JavaFX应用程序中已经初始化了JavaFX工具包。


  • 详细答案

    首先,不是您“重写”了 main类的 Application方法的情况。 Application类没有 main方法。实际发生的情况是,只要应用程序声明的主类是 Application的子类,Java就会使用它自己的主类。为了后代,可以使用以下方法之一声明主类:
  • 在命令行(文件)上指定:java -cp <classpath> foo.Main
  • 在命令行(模块)上指定:java -p <modulepath> -m foo/foo.Main
  • 在JAR清单中指定它:Main-Class: foo.Main
  • (另一种我忘记的方式?)

  • 步骤

    这些步骤假定使用JavaFX应用程序。如果启动“常规” Java应用程序,则大多数情况不会发生。

    步骤1:加载主类

    内部类 LauncherHelper通过名为 checkAndLoadMain的方法检查并加载主类。此方法负责根据声明主类的方式解析主类(如上所述)。找到后,此方法将检查主类是否为 Application的子类。如果是,则将 主类更改为静态内部类LauncherHelper$FXHelper:。然后执行一些验证,并将 Class返回到本机代码。

    相关代码:
  • java.base/sun.launcher.LauncherHelper
  • java.base/sun.launcher.LauncherHelper.checkAndLoadMain
  • java.base/sun.launcher.LauncherHelper$FXHelper

  • 步骤2:调用 main方法

    找到,加载和验证主类后,将从(我假设)本机代码中调用它。由于我们正在谈论JavaFX应用程序,因此现在的主要类是 LauncherHelper$FXHelper。此类的 main方法完成了一件简单的事情:通过反射调用内部JavaFX代码。

    相关代码:
  • java.base/sun.launcher.LauncherHelper$FXHelper.main

  • 步骤3:JavaFX预启动

    步骤2调用的代码在名为 LauncherImpl的类内;具体来说就是 launchApplication(String,String,String[])方法。此方法似乎与 LauncherHelper.checkAndLoadMain相似,但更特定于JavaFX。

    我相信此方法类似于 checkAndLoadMain,因为 checkAndLoadMain方法验证了 FXHelper类,这显然是有效的。但是, launchApplication需要验证 Application子类。

    相关代码:
  • javafx.graphics/com.sun.javafx.application.LauncherImpl
  • javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication

  • 步骤4:JavaFX启动

    下一个调用的方法是 launchApplicationWithArgs(ModuleAccess,String,String,String[])。此方法负责启动JavaFX工具包。此后,它将加载 Application子类以及 Preloader子类(如果存在)作为实际 Class实例。它在JavaFX Application Thread上执行此操作,然后返回到主线程。

    然后,代码将根据 main子类中是否存在 Application方法采用两条路径之一:
  • 存在main方法:继续执行步骤5。
  • 不存在main方法:继续执行步骤6(直接启动应用程序)

  • 相关代码:
  • javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs

  • 步骤5:调用 main子类的 Application方法(可选)

    如果 main子类中存在 Application方法,则通过反射调用它。开发人员现在有责任通过调用 Application.launch来继续启动过程。 launch方法有两个重载:
  • Application.launch(String...)
  • Application.launch(Class,String)

  • 唯一的不同是第一个选项使用调用的 Class作为JavaFX Application子类。两者最终都调用 LauncherImpl.launchApplication(Class,String[])。后一种方法仅在需要时加载 ClassPreloader,然后继续进行下一步。

    相关代码:
  • javafx.graphics/javafx.application.Application.launch(String...)
  • javafx.graphics/javafx.application.Application.launch(Class,String...)
  • javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
  • 注意:与步骤3中链接的方法不同。

  • 步骤6:完成启动JavaFX应用程序

    现在我们在 LauncherImpl.launchApplication(Class,Class,String[])方法中。此方法做两件事:
  • 创建并启动JavaFX-Launcher线程,该线程调用另一个方法
  • LauncherImpl.launchApplication1(Class,Class,String[])
  • 将主线程(或称为Application.launch的任何线程)停在CountDownLatch中,直到JavaFX工具包退出为止。

  • 如果尚未启动 launchApplication1方法,它将启动JavaFX工具包。然后继续执行标准的JavaFX生命周期。这涉及到创建 ApplicationPreloader类(如果存在),然后在适当的时间在适当的线程上调用 init()start(Stage)方法。这个生命周期是公开定义的行为;实际上,这里提到的所有其他内容都是实现细节。

    相关代码:
  • javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication
  • 注意:同样,与步骤3和5中链接的方法不同。
  • 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工具箱的原因,因为在这种情况下不会启动它。

    关于java - JavaFX运行时主要方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52434404/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com