我想了解抽象类Application的launch()方法在JavaFX中如何工作

问题描述 投票:0回答:1

在javaFX中Application是一个抽象类。在这个抽象类中,有一些抽象方法在扩展抽象应用程序类的主类中被重写,并且在抽象类应用程序中也有静态 launch() 方法。 launch() 方法从主类中的 main 方法调用。现在 launch() 方法如何调用这些抽象方法,并且对于这些调用,执行主类中的重写方法?请帮助我了解这个程序实际上是有效的。 我知道非静态方法不能从静态方法调用,并且不可能创建抽象类的实例。抽象方法不能是静态方法。

我不想创建主类的对象。因为launch()方法不知道主类的名字是什么。

给我写一段java代码,其中这个过程可以很好地说明。像这样

public class main extends Application{
    public static void main(String[] args)
        launch();                       // launch() was a static method in Application class
    }
    @override
    public void init(){                 // init() was an abstract method in Application class
        System.out.println("hello");
    }
}

public abstract class Application {
    public static void launch(){
        init();
    }
    public abstract void init();
}

我想获得输出:你好

java javafx abstract-class static-methods abstract-methods
1个回答
1
投票

Application#launch(String...)
方法定义为:

启动独立应用程序。此方法通常从

main
方法调用。 [...]。这相当于
launch(TheClass.class, args)
,其中
TheClass
是调用 launch 的方法的直接封闭类。

因此,它确实通过获取“调用者类”来知道主类的名称。然后,它通过反射创建应用程序类的实例,并根据需要调用 init()

start(Stage)
 方法。

Application

子类的实例化以及
init()
start(Stage)
stop()
的调用都是
JavaFX生命周期的一部分(由Application
记录)
。您不实例化应用程序类,也不调用这些方法。它由 JavaFX 处理。

请注意,您不应该拥有自己的

Application

 课程。将类命名为与您正在使用的框架中的类相同的名称不仅会令人困惑,而且对您没有任何帮助。如果您想要正常的 JavaFX 生命周期,您需要延长 
javafx.application.Application

JavaFX 是如何做到的?

这里有一些非 JavaFX 代码演示了该过程。请注意,它被大大简化了,并且与实际的 JavaFX 实现略有不同。

package com.example; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; public abstract class Application { private static final AtomicBoolean LAUNCHED = new AtomicBoolean(); private static Throwable error; public static void launch(Class<? extends Application> appClass, String... args) { Objects.requireNonNull(appClass); Objects.requireNonNull(args); if (!LAUNCHED.compareAndSet(false, true)) { throw new IllegalStateException("already launched"); } CountDownLatch startLatch = new CountDownLatch(1); Thread eventThread = new Thread(() -> { try { Application instance = appClass.getConstructor().newInstance(); instance.start(args); } catch (Throwable error) { Application.error = error; } finally { startLatch.countDown(); } }); eventThread.setName("Application Event Thread"); eventThread.start(); try { startLatch.await(); } catch (InterruptedException ex) { throw new RuntimeException(ex); } if (error != null) { throw new RuntimeException("Exception in Application start method", error); } } @SuppressWarnings("unchecked") public static void launch(String... args) { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); Class<?> callerClass = walker.getCallerClass(); if (!Application.class.isAssignableFrom(callerClass)) { throw new IllegalStateException("caller class is not a subclass of com.example.Application"); } launch((Class<? extends Application>) callerClass, args); } public abstract void start(String[] args); }
然后其他一些代码可以做到:

package com.example; import java.util.Arrays; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(String[] args) { System.out.println("Started! args = " + Arrays.toString(args)); } }
无需将课程传递给

launch

如上所述,这与 JavaFX 实际所做的相比大大简化,并且它使用了一些不同的 API。例如:

  • 我使用了

    java.lang.StackWalker

    (在Java 9中添加)。 JavaFX 目前(截至 21-ea)仍然使用通过 
    Thread.currentThread().getStackTrace()
     手动遍历堆栈跟踪的代码。

  • JavaFX 应用程序线程 不是像我上面的“应用程序事件线程”那样手动创建的。相反,FX 线程由 JavaFX 框架管理,真正的启动代码使用 Platform#runLater(Runnable)

     的内部版本。

    • 但是,真正的 JavaFX 代码确实执行了与我为用于调用

      init()

       方法的“JavaFX-Launcher Thread”所做的类似操作。

    • 我的代码有“应用程序事件线程”实例化该类,调用

      start(String[])

      ,然后死亡(一旦
      start
      返回)。这不是 
      JavaFX 应用程序线程 的工作方式,它本质上是在循环中运行。

  • 真正的 JavaFX 代码必须处理潜在的

    Preloader

  • 真正的 JavaFX 代码创建一个

    Stage

     实例,并将其传递给 
    start(Stage)
     方法;我通过传递给定的命令行参数数组来“模拟”这一点。但请注意,在真实的 JavaFX 应用程序中,如果将命令行参数传递给 
    launch
    ,那么这些参数将封装在 
    Parameters
     对象中(并进行基本解析)。

如果您真的对整个过程感到好奇,那么我建议您

遵循源代码

© www.soinside.com 2019 - 2024. All rights reserved.