为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

临摹微笑 2021-09-03 15:16:38
我有以下代码。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).为什么会这样?
查看完整描述

1 回答

?
胡子哥哥

TA贡献1825条经验 获得超6个赞

从您调用的方式来看,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.

         */

    }


}


查看完整回答
反对 回复 2021-09-03
  • 1 回答
  • 0 关注
  • 257 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信