我尝试从 Visual Studio Code 中使用 JavaFX 的项目创建一个 jar 文件。当我在 VSCode 中运行该应用程序时,它工作正常,但是当我将其导出到 jar 文件时,它会抛出错误:
错误:加载主类 HelloFX 时发生 LinkageError java.lang.UnsupportedClassVersionError:未为 HelloFX 启用预览功能(类文件版本 65.65535)。尝试使用“--enable-preview”运行
所以我收集这个错误是因为我用比我的JRE更新的版本编译了jar文件..但是当我使用“javac -version”和“java -version”时我得到相同的(21.0.2)(这已经是在我的系统变量 JAVA_HOME 和 Path 变量中设置)..我还发现我需要在 launch.json 文件的 vmArgs 参数中添加 '--enable-preview' (现在全文为: "vmArgs": "-- enable-preview --module-path "C:/Program Files/Java/javafx-sdk-21.0.2/lib" --add-modules javafx.controls,javafx.fxml" 因为我还需要添加 javafx sdk )
我创建了一个新项目来显示我的 java 版本和 javaFX 版本
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloFX extends Application {
@Override
public void start(Stage stage) {
String javaVersion = System.getProperty("java.version");
String javafxVersion = System.getProperty("javafx.version");
Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
Scene scene = new Scene(new StackPane(l), 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Run Code Online (Sandbox Code Playgroud)
当我在 VSCode 中运行它时,标签内的文本给我:“Hello, JavaFX 21.0.2, running on Java 21.0.2”,但作为 jar 文件运行时出现同样的错误
我在 VSCode 中配置了 Java 运行时(Java:Configure java Runtime)并将版本设置为 21
我不使用 Maven 或 Gradle(无构建工具),因为我真的不知道它们是如何工作的。
使用命令行时我使用“java -jar MyApp.jar”
我错过了什么吗?
前言:以下所有内容均假设您已按照JavaFX 入门中的说明来设置项目,特别是以下说明:
\nTL;DR:您没有使用任何预览功能,因此您需要停止--enable-preview传递给编译器。您可以通过以下方式执行此操作:
在项目目录中创建一个.settings/org.eclipse.jdt.core.prefs文件(如果该文件尚不存在)。
将以下行添加到该文件中:
\norg.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled\nRun Code Online (Sandbox Code Playgroud)\n如果您决定使用预览功能,则要么不执行上述操作,要么更改disabled为enabled. --enable-preview但在这种情况下,您也必须在运行时通过。
java --enable-preview --module-path <path-to-javafx-sdk>\\lib --add-modules <mods> -jar <jarfile>\nRun Code Online (Sandbox Code Playgroud)\n重要提示:该命令假定您没有在 JAR 文件中包含 JavaFX。
\n预览功能的概念是在 Java 12 左右添加的。以下是链接的 JEP 的摘要:
\n\n\n预览功能是 Java 语言、Java 虚拟机或 Java SE API 的一项新功能,它是完全指定、完全实现的,但不是永久的。它在 JDK 功能版本中可用,以激发开发人员根据实际使用情况提供反馈;这可能会导致它在未来的 Java SE 平台中永久存在。
\n
预览功能是可选的。换句话说,您必须明确告诉 Java 您想要在编译时和运行时使用预览功能。这是通过传递--enable-preview参数来完成的。如果类文件指示在编译时启用了预览功能,而您未能在运行时启用它们,那么您将看到收到的错误。
您可以在https://openjdk.org/projects/jdk/21/上查看哪些 Java 21 功能处于预览状态。例如,JEP 430:字符串模板(预览版)就是此类功能之一。使用该功能可以让您创建Label类似的内容:
Label l = new Label(STR."Hello, JavaFX \\{javafxVersion}, running on Java \\{javaVersion}.");\nRun Code Online (Sandbox Code Playgroud)\n您正在编译代码,--enable-preview但在执行 JAR 文件时未能传递相同的选项。但是,您的示例代码未使用任何 Java 21 预览功能,因此您可以通过运行以下命令来解决错误:
java --enable-preview --module-path <path-to-javafx-sdk>\\lib --add-modules <mods> -jar <jarfile>\nRun Code Online (Sandbox Code Playgroud)\n重要提示:该命令假定您没有在 JAR 文件中包含 JavaFX。
\n这并不能解决根本问题,即--enable-preview尽管您没有明显的意图,但该问题仍被传递给编译器。
您很可能正在使用Red Hat 扩展的 Java(TM) 语言支持。由于您没有使用 Maven 或 Gradle,因此您的项目显然被称为“Eclipse 项目”。本文档意味着您必须显式启用此类项目的预览功能:
\n\n\n\nEclipse 项目需要添加以下首选项
\n.settings/org.eclipse.jdt.core.prefs:Run Code Online (Sandbox Code Playgroud)\neclipse.preferences.version=1\norg.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\norg.eclipse.jdt.core.compiler.codegen.targetPlatform=20\norg.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\norg.eclipse.jdt.core.compiler.compliance=20\norg.eclipse.jdt.core.compiler.debug.lineNumber=generate\norg.eclipse.jdt.core.compiler.debug.localVariable=generate\norg.eclipse.jdt.core.compiler.debug.sourceFile=generate\norg.eclipse.jdt.core.compiler.problem.assertIdentifier=error\norg.eclipse.jdt.core.compiler.problem.enumIdentifier=error\norg.eclipse.jdt.core.compiler.release=enabled\norg.eclipse.jdt.core.compiler.source=20\n\norg.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=enabled\norg.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore\n
\n\n仅当使用 Java 16 并且该项目也是非托管的(例如,不是 Maven、Gradle 等)时,我们才会强制
\norg.eclipse.jdt.core.compiler.problem.enablePreviewFeatures执行。enabled
该评论有点旧,因此提到的 Java 版本可能已经过时了。我的理解是,预览功能只会在最新支持的 Java 版本上强制启用,即本答案时的 Java 21。您的项目使用 Java 21 并且是非托管的,因此它满足启用预览功能的条件。
\n解决方案是将“Eclipse 项目”配置为不启用预览功能。根据启用预览功能的文档以及对先前链接问题的另一条评论,您需要执行以下操作来禁用预览功能:
\n.settings/org.eclipse.jdt.core.prefs如果文件尚不存在,则创建一个文件。
将以下行添加到该文件中:
\norg.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled\nRun Code Online (Sandbox Code Playgroud)\n该.settings目录必须直接位于您的项目目录下。请注意,由于该目录是隐藏的(以 开头.),因此它可能不会显示在 VS Code 的资源管理器视图中。我不知道如何让它显示在该视图中,但您可以通过执行以下命令在 VS Code 中打开该文件:
code .settings/org.eclipse.jdt.core.prefs\nRun Code Online (Sandbox Code Playgroud)\n在终端中(上面假设项目目录是当前目录)。
\n禁用预览功能后,重建项目并导出新的 JAR 文件。您应该能够使用以下命令运行它:
\njava --module-path <path-to-javafx-sdk>\\lib --add-modules <mods> -jar <jarfile>\nRun Code Online (Sandbox Code Playgroud)\n重要提示:该命令假定您没有在 JAR 文件中包含 JavaFX。
\n现在没有问题。--enable-preview此外,您现在可以从 中的 VM 参数中删除launch.json。
javacOpenJDK 自带的编译器名为javac. 然而,RedHat VS Code 扩展使用 ECJ(与 Eclipse 不同的编译器实现)来编译代码,至少对于“Eclipse 项目”是这样。显然,两个编译器之间的行为存在差异。根据我的经验:
javac如果源文件实际上并未“使用”(由JEP 12定义)任何预览功能,则不会记录已启用的预览功能,即使--enable-preview已通过。
--enable-preview如果通过,ECJ 将无条件记录启用的预览功能。
用于启动 JAR 文件的上述所有命令均假定您未在 JAR 文件中包含 JavaFX(即,在将项目导出到 JAR 文件时取消选择 JavaFX JAR 文件)。这意味着您必须在命令行上指定--module-path要包含的模块和模块。--add-modules这不是很方便,但是如果您想创建一个所谓的 fat/uber/shadowed JAR 文件,那么您必须做一些事情。
创建一个单独的启动器类。该类必须是您的主类,而不是的子类javafx.application.Application。它至少必须做的就是启动 JavaFX 应用程序。
package hellofx;\n\nimport javafx.application.Application;\n\npublic class Launcher {\n\n public static void main(String[] args) {\n Application.launch(HelloFX.class, args);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这是必需的,因为 JavaFX在技术上不支持加载到未命名模块中。有一些内部代码检查主类是否是 的子类Application,如果是,则检查该javafx.graphics模块是否位于引导模块层。如果该模块不存在,则会失败。以上是一个解决方法。
您必须在 JAR 文件中包含 JavaFX 的本机代码。我找不到通过 VS Code 的“导出 JAR”功能来做到这一点的方法,但您可以在创建 JAR 文件后执行以下命令来添加本机代码:
\njar -uf <jarfile> -C <path-to-javafx-sdk>\\bin .\nRun Code Online (Sandbox Code Playgroud)\n警告:该命令将包含binJavaFX SDK 目录中的所有内容。例如,这意味着javafx.web即使您不需要它,它将包含模块的本机代码。但我根本不知道哪个共享库与哪个 JavaFX 模块对应。
完成这两件事后,然后执行:
\njava -jar <jarfile>\nRun Code Online (Sandbox Code Playgroud)\n应该有效(包括--enable-preview您决定使用预览功能的情况)。不过请注意,您会收到一条警告,您可以在此处阅读:JavaFX 警告:不支持的 JavaFX 配置:类是从 '未命名的模块 @...' 加载的。