如何修复 Java 中的 'no main manifest attribute' 错误

JavaJavaBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

当将 Java 应用程序打包并作为 JAR(Java Archive)文件运行时,开发者经常会遇到 'no main manifest attribute' 错误。当尝试执行 JAR 文件时,如果 Java 虚拟机(JVM)无法确定哪个类包含 main 方法来启动应用程序,就会发生此错误。

本实验将指导你理解、诊断和解决这个常见错误。通过本教程,你将知道如何使用清单文件正确配置 JAR 文件,从而正确指定主类。

创建一个简单的 Java 应用程序

让我们从创建一个简单的 Java 应用程序开始,我们将把它打包成一个 JAR 文件。这将帮助我们演示并稍后修复 'no main manifest attribute' 错误。

创建 Java 类

首先,为我们的 Java 源代码文件创建一个目录,并导航到该目录:

cd ~/project/src/com/example

现在,打开编辑器并在该目录中创建一个名为 HelloWorld.java 的新文件:

  1. 点击 WebIDE 左侧边栏中的 "Explorer" 图标
  2. 导航到 /home/labex/project/src/com/example
  3. 右键单击并选择 "New File"
  4. 将文件命名为 HelloWorld.java

将以下代码添加到 HelloWorld.java 文件中:

package com.example;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

这是一个基本的 Java 程序,它有一个 main 方法,当执行时,它将向控制台打印 "Hello, World!"。

编译 Java 类

现在,让我们编译我们的 Java 类。返回到终端并导航到项目根目录:

cd ~/project

使用 javac 命令编译 Java 文件:

javac -d . src/com/example/HelloWorld.java

此命令编译 Java 源代码文件,并根据包名将编译后的类文件放置在适当的目录结构中。

你现在应该在 ~/project/com/example/HelloWorld.class 处有一个编译后的类文件。你可以使用以下命令进行验证:

ls -l com/example/

输出应该显示 HelloWorld.class 文件:

total 4
-rw-r--r-- 1 labex labex 426 [date] HelloWorld.class

创建一个没有清单文件的基本 JAR 文件

现在,让我们创建一个 JAR 文件,而不指定清单文件中的主类。这将允许我们重现 'no main manifest attribute' 错误:

jar cf HelloWorld.jar com/

此命令创建一个名为 HelloWorld.jar 的 JAR 文件,其中包含编译后的类文件。

尝试运行 JAR 文件

现在我们已经创建了我们的 JAR 文件,让我们尝试运行它:

java -jar HelloWorld.jar

你将看到错误消息:

no main manifest attribute, in HelloWorld.jar

这就是我们正在学习修复的错误。JVM 找不到要执行的 main 类,因为我们没有在 JAR 的清单文件中指定它。

理解 'no main manifest attribute' 错误

在这一步中,我们将探讨 'no main manifest attribute' 错误的原因,并了解 JAR 文件清单的工作原理。

什么是清单文件?

JAR 文件在 META-INF 目录中包含一个名为 MANIFEST.MF 的特殊文件。此清单文件包含有关 JAR 及其内容的元数据。清单可以包含的一个重要信息是 Main-Class 属性,它告诉 JVM 哪个类包含在运行 JAR 时要执行的 main 方法。

让我们检查一下我们 JAR 文件中的当前清单:

mkdir -p temp_dir
cd temp_dir
jar xf ../HelloWorld.jar META-INF/MANIFEST.MF
cat META-INF/MANIFEST.MF

你将看到一个最小的清单,它看起来像这样:

Manifest-Version: 1.0
Created-By: 1.8.0_XXX (Oracle Corporation)

请注意,此清单中没有 Main-Class 属性,这就是我们在尝试运行 JAR 时收到 'no main manifest attribute' 错误的原因。

如何查看 JAR 文件的内容

为了更好地理解我们的 JAR 文件,让我们看看它的内容:

cd ~/project
jar tf HelloWorld.jar

此命令列出 JAR 中的所有文件。输出应该类似于:

META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/HelloWorld.class

正如我们所看到的,我们的 JAR 包含编译后的类文件,正如预期的那样,但清单没有识别主类所需的信息。

什么时候发生此错误?

'no main manifest attribute' 错误通常发生在以下情况:

  1. 创建 JAR 文件时,未在清单中指定主类
  2. 尝试使用 java -jar 运行 JAR 文件,但 JAR 并非旨在可执行
  3. 清单文件存在,但未包含 Main-Class 属性

在我们的例子中,我们故意创建了一个 JAR,没有指定主类来演示该错误。

让我们清理我们的临时目录:

cd ~/project
rm -rf temp_dir

现在我们了解了错误的原因,在下一步中,我们将通过创建一个正确的清单文件来修复它。

创建清单文件

现在我们了解了问题,让我们通过创建一个指定主类的正确清单文件来修复它。

创建清单文件

首先,导航回项目目录:

cd ~/project

现在,创建一个名为 manifest.txt 的文本文件:

  1. 点击 WebIDE 左侧边栏中的 "Explorer" 图标
  2. 导航到 /home/labex/project
  3. 右键单击并选择 "New File"
  4. 将文件命名为 manifest.txt

将以下内容添加到 manifest.txt 文件中:

Main-Class: com.example.HelloWorld

确保在文件末尾添加一个换行符(清单格式要求文件以换行符结尾)。在 WebIDE 中,只需在键入以上行后按 Enter 键即可。

这个简单的清单文件指定了 com.example.HelloWorld 类包含在运行 JAR 时应该执行的 main 方法。

使用清单创建新的 JAR 文件

现在,创建一个新的 JAR 文件,这次包括我们的自定义清单:

jar cfm HelloWorldWithManifest.jar manifest.txt com/

此命令创建一个名为 HelloWorldWithManifest.jar 的新 JAR 文件,其中包含编译后的类文件,并使用我们的自定义清单文件。

此命令中使用的选项是:

  • c: 创建一个新归档文件
  • f: 指定归档文件名
  • m: 从指定的清单文件包含清单信息
  • 其余参数是要包含在 JAR 中的文件/目录

验证新 JAR 中的清单

让我们检查一下我们的清单是否已正确包含在 JAR 中:

mkdir -p temp_check
cd temp_check
jar xf ../HelloWorldWithManifest.jar META-INF/MANIFEST.MF
cat META-INF/MANIFEST.MF

你应该看到清单现在包括我们的 Main-Class 属性:

Manifest-Version: 1.0
Created-By: [Java version info]
Main-Class: com.example.HelloWorld

现在,让我们清理临时目录:

cd ~/project
rm -rf temp_check

运行已修复的 JAR 文件

现在我们已经创建了一个具有指定主类的正确清单文件的 JAR 文件,让我们运行它并验证它是否正常工作。

运行 JAR 文件

确保你在项目目录中:

cd ~/project

现在,使用 java -jar 命令运行 JAR 文件:

java -jar HelloWorldWithManifest.jar

这次,你不会看到 'no main manifest attribute' 错误,你应该看到我们程序的输出:

Hello, World!

恭喜你。你已经通过创建一个指定主类的正确清单文件,成功修复了 'no main manifest attribute' 错误。

理解我们修复了什么

让我们花点时间来理解我们做了什么来修复这个错误:

  1. 我们创建了一个清单文件,其中包含 Main-Class 属性,告诉 JVM 哪个类包含要执行的 main 方法
  2. 我们创建了一个新的 JAR 文件,其中包含此清单信息
  3. 我们使用 java -jar 命令运行了 JAR,并且 JVM 能够找到并执行 main 方法

指定主类的其他方法

在使用 JAR 文件时,还有其他几种指定主类的方法:

方法 1:在创建 JAR 时指定主类

除了创建单独的清单文件之外,你还可以使用 e 选项在创建 JAR 时直接指定主类:

jar cfe HelloWorldDirect.jar com.example.HelloWorld com/

这将创建一个名为 HelloWorldDirect.jar 的新 JAR 文件,其主类指定为 com.example.HelloWorld

让我们运行这个 JAR 来验证它是否有效:

java -jar HelloWorldDirect.jar

你应该看到输出:

Hello, World!

方法 2:在不使用清单的情况下运行 JAR

如果你有一个没有正确清单的 JAR 文件,你仍然可以通过在 java 命令中直接指定主类来运行它:

java -cp HelloWorld.jar com.example.HelloWorld

此命令告诉 JVM 在类路径 (-cp) 中使用 HelloWorld.jar 并执行 com.example.HelloWorld 类。

你应该看到输出:

Hello, World!

这种方法通过显式地告诉 JVM 要执行哪个类来绕过对清单的需求。

总结

在这个实验中,你学习了 Java 中的 'no main manifest attribute' 错误以及如何解决它。让我们回顾一下我们所涵盖的内容:

  1. 理解错误:当 JVM 无法在 JAR 文件中找到要执行的 main 类时,就会发生 'no main manifest attribute' 错误,因为它未在清单中指定。

  2. 创建正确的清单:你学习了如何使用 Main-Class 属性创建一个指定主类的清单文件。

  3. 使用清单构建 JAR 文件:你学习了如何创建包含清单信息的 JAR 文件:

    • 使用单独的清单文件 (jar cfm ...)
    • 在 JAR 创建期间直接指定主类 (jar cfe ...)
  4. 运行 JAR 文件:你学习了以不同方式运行打包为 JAR 文件的 Java 应用程序:

    • 使用 java -jar 和正确配置的清单
    • 使用 java -cp 显式指定类路径和主类

这些技能对于需要将应用程序打包并分发为 JAR 文件的 Java 开发人员至关重要。通过理解清单的作用以及如何正确配置它,你可以避免 'no main manifest attribute' 错误,并确保你的 Java 应用程序顺利运行。

请记住,正确的打包与编写好的代码一样重要。花时间正确设置你的构建和打包将为你和你的用户节省以后的麻烦。