JavaFX 本机打包 - 初始化静态变量时出现奇怪错误
JavaFX native packaging - bizarre error with initialising static variables
我正在 Netbeans 中开发一个 JavaFX 项目,该项目目前大约有 3000 行,并且我定期打包为 .exe 进行测试,但从未遇到过像这种奇怪事件这样的问题。
当本机打包为 Windows .exe 文件时,我发现在安装 .exe 并启动我的程序后,我收到一个弹出窗口,上面写着“Class {mypackage }/{mymainclass} 未找到。”后跟“无法启动 JVM。”
在 Netbeans 中启动程序,打包为 .exe,并在 Powershell 中使用 "java -jar {app}.jar" 启动 .jar 都绝对没有错误。即使安装的应用程序文件夹中的 .jar 也很好,命令行上没有错误。
在对 git 提交和本地打包进行拖网搜索几个小时后,我设法将问题追溯到一行代码:
private static ComboBox choices = new ComboBox();
当我在初始化程序中初始化 ComboBox 时,该程序在从 .exe 安装后神奇地工作:
private static ComboBox choices;
{
choices = new ComboBox();
}
但是,当我使用静态初始化器(通过将 static
放在第一个大括号前面)时,即使 Netbeans 声明 "initialiser can be static",我也会遇到与以前相同的错误。
这很令人费解,因为 Java 代码本身显然没问题,但是在通过本机打包程序后它不会启动。我已经使用了大量类似的代码行来初始化其他 classes 中的静态变量,没有任何不良影响。
我尝试在主 class 中添加类似的行:private static CheckBox chkbox = new CheckBox();
它在安装 .exe 后引起了完全相同的错误(和以前一样,.jar 没问题),但是当我将该行剪切并粘贴到另一个 class 时,它没有效果。
有趣的是,我的主要 class 已经有一个静态布尔值,它的初始化方式与 ComboBox 和 CheckBox 的初始化方式相同:private static boolean someBool = true;
但布尔值没有问题。
谁能解释一下这背后的原因?谢谢。
编辑:我也尝试在另一台机器上打包,但在相同的 git 提交后它停止工作。
我正在使用 JDK 和 JRE.
的 1.8.0_144 版本
编辑 2:这是产生错误的简单示例的主要部分 class。
package testproject;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainApplication extends Application {
private static CheckBox testCheckBox = new CheckBox(); // Causes error after launching from installed .exe
/* UNCOMMENT THIS SECTION AND REMOVE THE " = new CheckBox()" ABOVE TO FIX THE ERROR
{
testCheckBox = new CheckBox();
}
*/
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Empty window");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我会避免在静态初始化程序(例如静态字段或静态块)中创建 JavaFX 小部件,因为这会在 class 已加载,这可能发生在任何线程 中。您希望在 JavaFX 应用程序线程中发生这种情况。
在你的情况下,它发生在主线程中,这绝对是不正确的。
查看 了解有关 JavaFX 应用程序启动以及线程如何参与进程的更多详细信息。
尝试在 "JavaFX Application Thread" 之外初始化 JavaFX 小部件(据我所知)是未定义的行为,并且可能会以多种不同的方式失败(或靠运气成功)。如果创建失败,则 class 加载失败(因为静态初始化失败),因此 "class not found"。不幸的是,由于这种情况发生在加载 main class 时,您看不到初始错误,只能看到 "class XXX not found".
可能在您的情况下,java
启动器可以很好地处理此初始化,但您的 .exe 使用的启动器不同。我对它失败并不感到惊讶。我同样惊讶它可以与常规 java 一起使用 :)
我正在 Netbeans 中开发一个 JavaFX 项目,该项目目前大约有 3000 行,并且我定期打包为 .exe 进行测试,但从未遇到过像这种奇怪事件这样的问题。
当本机打包为 Windows .exe 文件时,我发现在安装 .exe 并启动我的程序后,我收到一个弹出窗口,上面写着“Class {mypackage }/{mymainclass} 未找到。”后跟“无法启动 JVM。”
在 Netbeans 中启动程序,打包为 .exe,并在 Powershell 中使用 "java -jar {app}.jar" 启动 .jar 都绝对没有错误。即使安装的应用程序文件夹中的 .jar 也很好,命令行上没有错误。
在对 git 提交和本地打包进行拖网搜索几个小时后,我设法将问题追溯到一行代码:
private static ComboBox choices = new ComboBox();
当我在初始化程序中初始化 ComboBox 时,该程序在从 .exe 安装后神奇地工作:
private static ComboBox choices;
{
choices = new ComboBox();
}
但是,当我使用静态初始化器(通过将 static
放在第一个大括号前面)时,即使 Netbeans 声明 "initialiser can be static",我也会遇到与以前相同的错误。
这很令人费解,因为 Java 代码本身显然没问题,但是在通过本机打包程序后它不会启动。我已经使用了大量类似的代码行来初始化其他 classes 中的静态变量,没有任何不良影响。
我尝试在主 class 中添加类似的行:private static CheckBox chkbox = new CheckBox();
它在安装 .exe 后引起了完全相同的错误(和以前一样,.jar 没问题),但是当我将该行剪切并粘贴到另一个 class 时,它没有效果。
有趣的是,我的主要 class 已经有一个静态布尔值,它的初始化方式与 ComboBox 和 CheckBox 的初始化方式相同:private static boolean someBool = true;
但布尔值没有问题。
谁能解释一下这背后的原因?谢谢。
编辑:我也尝试在另一台机器上打包,但在相同的 git 提交后它停止工作。 我正在使用 JDK 和 JRE.
的 1.8.0_144 版本编辑 2:这是产生错误的简单示例的主要部分 class。
package testproject;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainApplication extends Application {
private static CheckBox testCheckBox = new CheckBox(); // Causes error after launching from installed .exe
/* UNCOMMENT THIS SECTION AND REMOVE THE " = new CheckBox()" ABOVE TO FIX THE ERROR
{
testCheckBox = new CheckBox();
}
*/
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Empty window");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我会避免在静态初始化程序(例如静态字段或静态块)中创建 JavaFX 小部件,因为这会在 class 已加载,这可能发生在任何线程 中。您希望在 JavaFX 应用程序线程中发生这种情况。
在你的情况下,它发生在主线程中,这绝对是不正确的。
查看
尝试在 "JavaFX Application Thread" 之外初始化 JavaFX 小部件(据我所知)是未定义的行为,并且可能会以多种不同的方式失败(或靠运气成功)。如果创建失败,则 class 加载失败(因为静态初始化失败),因此 "class not found"。不幸的是,由于这种情况发生在加载 main class 时,您看不到初始错误,只能看到 "class XXX not found".
可能在您的情况下,java
启动器可以很好地处理此初始化,但您的 .exe 使用的启动器不同。我对它失败并不感到惊讶。我同样惊讶它可以与常规 java 一起使用 :)