猿问

为什么 javafx 忽略 main 的返回并仍然启动应用程序?

我有以下代码。


public static void main(String[] args)

{

    if (!ArgumentsHandler.handle(args))

    {

        return;

    }


    Storage.getInstance().load();


    if (!Storage.getInstance().isLoadSuccessful())

    {

        launch(args);

    }

    else

    {

        System.err.println("Unable to load configurations.");

    }

}

我特意将if语句中的条件倒置以使其失败,并且我在调试器中绝对可以看到它没有执行该launch方法,但应用程序窗口仍在显示。


我还注意到 using方法return内的语句main没有效果 - 应用程序仍然继续执行。它只响应System.exit(0).


为什么会这样?


临摹微笑
浏览 258回答 1
1回答

胡子哥哥

从您调用的方式来看,launch(args)我假设,并且您后来证实了这一点,该main方法位于Application. 我相信这是您问题的原因。正如您所注意到的,有很多看似 JavaFX 特定的线程正在运行。具体来说,非守护进程“JavaFX 应用程序线程”正在运行(至少,它在 Java 10 中是非守护进程)。即使该main线程退出,该线程也会使 JVM 保持活动状态。这是 Java 的正常行为:线程当 Java 虚拟机启动时,通常有一个非守护线程(通常调用main某个指定类的方法)。Java 虚拟机继续执行线程,直到发生以下任一情况:exit类的方法Runtime已被调用,安全管理器已允许退出操作发生。不是守护线程的所有线程都已死亡,无论是从对run方法的调用返回,还是通过抛出传播到run方法之外的异常。但是为什么“JavaFX 应用程序线程”在您故意不调用的情况下启动Application.launch?我只是在这里猜测,但这可能与 JavaFX 应用程序收到的特殊待遇有关。因为至少Java的8你没有申报main的子类中的方法Application1。如果主类是ApplicationJava的子类,则自动处理启动。import javafx.application.Application;import javafx.stage.Stage;public class MyApp extends Application {    @Override    public void start(Stage primaryStage) throws Exception {        // create scene and show stage...    }}如果您有上述并调用java MyApp应用程序将启动并被start调用。但是,如果您有以下情况:import javafx.application.Application;import javafx.stage.Stage;public class MyApp extends Application {    public static void main(String[] args) {}    @Override    public void start(Stage primaryStage) throws Exception {        // create scene and show stage...    }}然后main调用方法,但start就是没有。基本上,显式声明main会覆盖启动 JavaFX 应用程序的默认行为,但不会阻止 JavaFX 运行时被初始化。也许这种行为是设计好的,也可能是一种疏忽。但这里重要的是,只有当主类有一个main方法并且是一个Application子类时才会发生这种情况。如果将这两者分开:public class MyApp extends Application {    // implement ...}public class Main {    public static void main(String[] args) {        // Perform pre-checks, return if necessary        Application.launch(MyApp.class, args);    }}那么你将不再有这个问题。否则,您可以继续使用System.exit()或切换到Platform.exit().还有另一种可能更合适的方法来处理这个问题。您似乎main在调用之前在方法中执行初始化Application.launch。如果在此初始化过程中出现问题,您希望中止启动 JavaFX 应用程序。好吧,JavaFX 本身提供了执行此操作的方法:Application.init().应用程序初始化方法。在加载和构造 Application 类后立即调用此方法。应用程序可以覆盖此方法以在应用程序实际启动之前执行初始化。Application 类提供的这个方法的实现什么都不做。注意:此方法不会在 JavaFX 应用程序线程上调用。应用程序不得在此方法中构造场景或舞台。应用程序可以在此方法中构造其他 JavaFX 对象。将您的初始化代码移至此方法。如果您调用,Platform.exit()则应用程序将退出并且Application.start不会被调用。另一种方法是在init. 您还可以通过使用Application.getParameters()which 返回 的实例来获取应用程序参数Application.Parameters。public class MyApp extends Application {    @Override    public void init() throws Exception {        if (!ArgumentsHandler.handle(getParameters()) {            Platform.exit(); // or throw an exception        } else {            Storage storage = Storage.getInstance();            storage.load();            if (!storage.isLoadSuccessful()) {                Platform.exit(); // or throw an exception            }        }    }    @Override    public void start(Stage primaryStage) throws Exception {        // Create Scene and show the primary Stage    }    @Override    public void stop() throws Exception {        /*         * Called when the JavaFX application is exiting, such as from         * a call to Platform.exit(). Note, however, that in my experience         * this method is *not* called when Platform.exit() is called inside         * the "init" method. It is called if Platform.exit() is called from         * inside the "start" method or anywhere else in the application once         * it is properly started.         *         * This is where you could perform any necessary cleanup.         */    }}
随时随地看视频慕课网APP

相关分类

Java
我要回答