如果 MANIFEST.MF 不存在,主类的定义是什么

问题描述

在 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 属性的优点是:

  1. 如果您想使用 -jar,这是必要的。
  2. 这意味着用户不需要知道(或输入)入口点类的全名。

拥有 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> 等效的操作。

注意事项:

  1. 这是Eclipse 特定行为。标准的 Java 工具链不会做这样的事情。

  2. Eclipse 未在此处使用 java -jar,因此不会参考清单来查找入口点类。

  3. 众所周知,这会被打破。例如,我听说如果您删除主类并创建一个新类,则启动配置不会更新,并且在您尝试“运行”它时会出现 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 了解更多信息。