我正在学习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);
}
}
答案 0 :(得分:7)
LauncherImpl
调用Application#start
,但是通过PlatformImpl.runAndWait
将actuall调用放到JavaFX事件队列中。这是在Preloader
启动后完成的
Application#launch
调用LauncherImpl.launchApplication
,创建Thread
并调用launchApplication1
,launchApplication
然后等待此Thread
终止,通过CountDownLatch
。
此Thread
然后调用LauncherImpl.launchApplication1
,根据有关Preloader
调用状态{{1}的数量决定,如果指定,则启动Preloader
包含在Application#start
调用中,以确保在JavaFX的GUI /事件队列线程的上下文中调用runAndWait
...
这基于Java 8
<强>更新... 强>
由start
调用的 theApp.start
是您LauncherImpl.launcherApplication1
的实例。
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
实例并将其传递给Class.forName
...
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
的{{1}}方法....我知道很奇怪,但它就是
答案 1 :(得分:4)
JavaFX程序既不需要main()
方法也不需要调用Application.launch()方法。
您可以从应用程序中删除main()
方法,java application launcher将直接调用init()
(在启动程序线程上)和start()
(在JavaFX应用程序线程上) )应用程序的方法。执行此操作时,将跳过某些其他线程中讨论的整个LauncherImpl
进程(以及通过StackTrace查找启动的类的奇怪决定)。
请参阅相关的Java Enhancement Proposal JEP 153: "Enhance the java command-line launcher to launch JavaFX applications."及其随附的问题跟踪链接JDK-8001533 "java launcher must launch javafx applications"。
当然,如果除main()
方法之外还有start()
方法,那么代码目前将按照MadProgrammer在其答案中列出的路径进行。
在编写JavaFX程序时,最好假设永远不会调用main()
(尽管实际上,如果你没有部署为applet,很可能会调用main()
只是为了阻止人们完全糊涂。)
此过程也在Application javadoc:
中描述Java启动程序加载并初始化指定的Application JavaFX应用程序线程上的类。如果没有主要方法 Application类,或者main方法调用 然后是Application.launch(),然后是Application的一个实例 在JavaFX应用程序线程上构建。
答案 2 :(得分:2)
发布时,LauncherImpl
的源代码为here,第837行调用start(...)
方法。在源代码中,它非常严峻......
答案 3 :(得分:1)
添加到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()
。
已经删除了很多东西,因为源很多太长而无法在此处发布,但这是基本的调用链
答案 4 :(得分:0)
也只是学习JavaFx,我觉得它刚刚用你的类初始化,因为它是你主要参数之上的方法。我目前正在使用一个只包含主参数和start方法的简单类,没有其他命令,并且start方法似乎在编译时执行,但是应该在
上调用launch(args);
这是我的主要参数的全部内容,这就是为我执行start方法的方法