问题描述
在 Eclipse 中导出为 JAR 有两个选项:导出为可运行的 JAR 和导出为 JAR。
据我所知,可运行的 jar 包含一个 MANIFEST.MF 文件,该文件定义了执行 jar 时要执行的 Main 类。
我也明白不可运行的 jar 只是类库,可以将其添加到类路径中,以便重用代码。它包含一个清单文件,但其中没有定义的主类。
如果没有定义主类,一个不可运行的 JAR 文件如何能够执行?拥有定义主类的 MANIFEST.MF 文件的优缺点是什么?一个比另一个更稳定吗?
解决方法
如果 MANIFEST.MF 不存在,什么定义了主类
如果 JAR 文件没有“META-INF/MANIFEST.MF”组件,则它不是 JAR 文件。它只是一个 ZIP 文件,您不能将 java -jar ...
与 ZIP 文件一起使用。 (您可以在类路径中包含一个 ZIP 文件,但通常不会这样做。)
如果 JAR 文件的 MANIFEST.MF 没有 Main-Class
属性,则它不是 可执行 JAR 文件,java -jar ...
将失败。
但是(如前所述)许多 JAR 文件是库而不是应用程序。对他们来说,入门类毫无意义。
如果未定义主类,不可运行的 JAR 文件如何能够执行?
(首选的 Java 术语是“可执行”而不是“可运行”。)
在这种情况下,java -jar ...
将失败。相反,您可以像这样运行应用程序:
java -cp <classpath> <other-options> com.example.MyApp.Main <args>
其中 com.example.MyApp.Main
是主/入口点类,<classpath>
包括 JAR(或 ZIP)文件和任何其他运行时依赖项。
请注意,一个应用程序 JAR 文件可以包含多个入口点类,并且用户可以决定使用哪一个。
拥有定义主类的 MANIFEST.MF 文件的优缺点是什么?
首先,如果您使用 jar
命令创建 JAR 文件,那么它将有一个 MANIFEST.MF。该命令不会创建一个没有 JAR 的 JAR。
此外,您还可以在 MANIFEST.MF 中包含其他有用的内容。这些包括数字哈希(用于签名的 JAR)和一个 Class-Path
属性,用于在使用 -jar
启动 JAR 时使用。有关详细信息,请参阅 JAR file specification。
在 JAR 文件中具有 Main-Class
属性的优点是:
- 如果您想使用
-jar
,这是必要的。 - 这意味着用户不需要知道(或输入)入口点类的全名。
拥有 Main-Class
属性没有明显的缺点。如果用户不使用 java -jar ...
启动方法,则任何此类属性都将被忽略。但我想您可能会说,在 library JAR 上放置一个无意义的 Main-Class
属性可能会导致天真的用户收到误导性错误。这是头发分裂...
一个比另一个更稳定吗?
不直接。
您可能会争辩说,使用 -jar
更稳定,因为可执行 JAR 会忽略命令行上的 CLASSPATH
环境变量和 -cp
参数。但另一方面,您不能强制用户使用 -jar
(或双击)来启动命令。您可以通过提供 shell 脚本或 BAT 文件来启动具有适当入口点类名和适当类路径的应用程序,从而获得类似的稳定性。
我在没有类路径或项目文件的情况下在 Eclipse 中执行了一个不可运行的 jar,然后我运行它并且它工作正常。它能够识别主类并从那里运行它。我的问题是:它是如何识别它的?
好吧……那是一个不同的问题。
这里实际发生的是 Eclipse 项目有一堆配置信息,其中包括 build 依赖项。这些为 Eclipse 启动器提供了一个默认的类路径。然后,当您在没有现有运行配置的情况下使用 Eclipse 的 run
命令时,Eclipse 将搜索当前项目中的所有类,寻找具有 public static void main(String[])
方法的any 类。如果它只找到一个这样的类,它假定它是入口点类,并为项目/类创建一个运行配置。启动该配置后,Eclipse 会执行与 java -cp <classpath> <class-name> <args>
等效的操作。
注意事项:
-
这是Eclipse 特定行为。标准的 Java 工具链不会做这样的事情。
-
Eclipse 未在此处使用
java -jar
,因此不会参考清单来查找入口点类。 -
众所周知,这会被打破。例如,我听说如果您删除主类并创建一个新类,则启动配置不会更新,并且在您尝试“运行”它时会出现 JVM 启动错误。
“可运行 jar”是一个 jar 文件,其中清单文件包含允许 java
Java 运行程序命令以更简单的方式“运行”jar 文件的说明。
例如如果 Foo.jar
文件在包 static void main(String[])
中的类 Bar
中具有 com.example
方法,那么您可以使用以下命令运行该程序:
java -cp Foo.jar com.example.Bar
如果 jar 文件清单文件包含以下行:
Main-Class: com.example.Bar
然后你可以用更简单的方式运行 jar 文件:
java -jar Foo.jar
当然,如果没有带有 main()
方法的类,那么 jar 文件中的代码不是“可运行的”,因此只是一个库文件。
这就是它的全部。
参见例如The Java™ Tutorials - Setting an Application's Entry Point 了解更多信息。