[英]When does a JavaFX program call the start method?
我正在学习JavaFX。 我只能在main方法中看到启动(args)方法。 当我调试进入发布时。 我看不到任何语句调用start()。那么JavaFX程序何时调用start方法? 这是launch(args)源代码。
public static void launch(String... args) {
// Figure out the right class to call
StackTraceElement[] cause = Thread.currentThread().getStackTrace();
boolean foundThisMethod = false;
String callingClassName = null;
for (StackTraceElement se : cause) {
// Skip entries until we get to the entry for this class
String className = se.getClassName();
String methodName = se.getMethodName();
if (foundThisMethod) {
callingClassName = className;
break;
} else if (Application.class.getName().equals(className)
&& "launch".equals(methodName)) {
foundThisMethod = true;
}
}
if (callingClassName == null) {
throw new RuntimeException("Error: unable to determine Application class");
}
try {
Class theClass = Class.forName(callingClassName, true,
Thread.currentThread().getContextClassLoader());
if (Application.class.isAssignableFrom(theClass)) {
Class<? extends Application> appClass = theClass;
LauncherImpl.launchApplication(appClass, args);
} else {
throw new RuntimeException("Error: " + theClass
+ " is not a subclass of javafx.application.Application");
}
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
LauncherImpl
调用Application#start
#start,但是通过PlatformImpl.runAndWait
将actuall调用放到JavaFX事件队列中。 这是在Preloader
启动后完成的
Application#launch
调用LauncherImpl.launchApplication
,它创建一个Thread
并调用launchApplication1
,然后launchApplication
通过CountDownLatch
等待此Thread
终止。
然后,此Thread
调用LauncherImpl.launchApplication1
,如果指定,则启动Preloader
,然后根据有关Preloader
调用Application#start
runAndWait
状态的数字决定,包含在runAndWait
调用中,以确保在上下文中调用start
。 JavaFX的GUI /事件队列线程......
这基于Java 8
更新...
由LauncherImpl.launcherApplication1
调用的theApp.start
是Application
的实例。
Application
通过遍历StackTrace
来查找您的类名...所有事情......
StackTraceElement[] cause = Thread.currentThread().getStackTrace();
boolean foundThisMethod = false;
String callingClassName = null;
for (StackTraceElement se : cause) {
// Skip entries until we get to the entry for this class
String className = se.getClassName();
String methodName = se.getMethodName();
if (foundThisMethod) {
callingClassName = className;
break;
} else if (Application.class.getName().equals(className)
&& "launch".equals(methodName)) {
foundThisMethod = true;
}
}
这将获取您的类的名称,然后使用Class.forName
创建一个Class
实例并将其传递给LauncherImpl
...
launcherApplication1
然后构造此类的新实例并将其分配给引用theApp
,它是Application
一个实例
PlatformImpl.runAndWait(new Runnable() {
@Override public void run() {
try {
Constructor<? extends Application> c = appClass.getConstructor();
app.set(c.newInstance());
// Set startup parameters
ParametersImpl.registerParameters(app.get(), new ParametersImpl(args));
PlatformImpl.setApplicationName(appClass);
} catch (Throwable t) {
System.err.println("Exception in Application constructor");
constructorError = t;
error = true;
}
}
});
}
final Application theApp = app.get();
然后它继续调用theApp.start
,它调用你的Application
的start
方法....我知道很奇怪,但它是
JavaFX程序既不需要main()
方法也不需要调用Application.launch()方法。
您可以从应用程序中删除main()
方法, java应用程序启动器将直接调用应用程序上的init()
(在启动程序线程上)和start()
(在JavaFX应用程序线程上)方法。 执行此操作时,将跳过在某些其他线程中讨论的整个LauncherImpl
进程(以及通过StackTrace查找启动的类的奇怪决定)。
请参阅相关的Java Enhancement Proposal JEP 153:“增强java命令行启动程序以启动JavaFX应用程序。” 及其随附的问题跟踪链接JDK-8001533“java启动器必须启动javafx应用程序” 。
当然,如果除了start()
方法之外还有main()
方法,那么代码将在MadProgrammer的答案中沿着MadProgrammer概述的路径前进。
在编写JavaFX程序时,最好假设从不调用main()
(尽管实际上,如果你没有部署为applet,可能会调用main()
来阻止人们完全混淆)。
Application javadoc中还描述了此过程:
Java启动程序在JavaFX应用程序线程上加载并初始化指定的Application类。 如果Application类中没有main方法,或者main方法调用Application.launch(),则会在JavaFX Application Thread上构造Application的实例。
在发布时, LauncherImpl
的源代码在这里 ,第837行调用start(...)
方法。 在源代码中,它非常严峻......
要添加到MadProgrammer的答案:
Application.class
,第241行:
public static void launch(String... args) {
//...
if (Application.class.isAssignableFrom(theClass)) {
Class<? extends Application> appClass = theClass;
LauncherImpl.launchApplication(appClass, args); // <-- This is where the application is launched
//...
}
在这里( LauncherImpl.class
第118行):
public static void launchApplication(final Class<? extends Application> appClass,
final String[] args) {
launchApplication(appClass, savedPreloaderClass, args);
}
在这里(第158行):
public static void launchApplication(final Class<? extends Application> appClass,
final Class<? extends Preloader> preloaderClass,
final String[] args) {
//.......
Thread launcherThread = new Thread(new Runnable() {
@Override public void run() {
try {
launchApplication1(appClass, preloaderClass, args); // <-- go here
} catch (RuntimeException rte) {
//....
}
这是第674行的loooong方法:
private static void launchApplication1(final Class<? extends Application> appClass,
final Class<? extends Preloader> preloaderClass,
final String[] args) throws Exception {
//... Lots of stuff
// Eventually, on line 755:
currentPreloader.start(primaryStage);
// More things for cases where the previous start() call isn't appropriate
// Line 773:
final AtomicReference<Application> app = new AtomicReference<>();
// Line 790/791:
Constructor<? extends Application> c = appClass.getConstructor(); // Gets constructor for your class
app.set(c.newInstance()); // Creates a new instance of your class
// Line 803:
final Application theApp = app.get();
// Line 837:
theApp.start(primaryStage);
}
因为您的JavaFX项目扩展了Application
, appClass
应该是JavaFX项目的类对象,因此您定义的start()
方法将由theApp.start()
调用。
跳过了很多东西,作为源实在是太长了被张贴在这里,但是这电话的基本链
也只是学习JavaFx,我的印象是它只是用你的类初始化,因为它是一个高于你的主要参数的方法。 我目前正在使用一个只包含主参数和start方法的简单类,没有其他命令,并且start方法似乎在编译时执行,但是应该调用它
launch(args);
这是我的主要参数的全部内容,这就是为我执行start方法的方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.