如果 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 启动错误。