我构建了我的项目并使用 Gradle 构建框架生成了一个 JAR 文件。但是,在这种情况下,输出 jar 文件无法从主类 ( miner.Tracker ) 加载主要方法。
正如我所提到的,使用-jar选项运行失败。
-jar
$ java -jar Backtracker.jar Error: Could not find or load main class miner.Tracker
我也尝试使用-cp选项直接运行该类,但失败了。
-cp
$ java -cp Backtracker.jar miner.Tracker Error: Could not find or load main class miner.Tracker
最后,我解压缩了 jar 文件并从内部调用了该类。这一次,它已经成功找到并运行了 main 方法的类。
$ mkdir classes $ cd classes $ classes $ tar xvf ../Backtracker.jar x META-INF/ x META-INF/MANIFEST.MF x CHANGELOG.md x com/ 1. ... classes $ java miner.Tracker 2021-04-12 22:47:48.008 | Logging started ...
这是META-INF/MANIFEST.MF文件的内容。
META-INF/MANIFEST.MF
Manifest-Version: 1.0 Implementation-Title: BackTracker Implementation-Version: 1.9.xx Specification-Title: release Specification-Version: 1.9.xx Main-Class: miner.Tracker
我正在从 Oracle Java 1.8 运行它。
$ java -version java version "1.8.0_271" Java(TM) SE Runtime Environment (build 1.8.0_271-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
谢谢你的帮助。
更新:
$ tar tvf Backtracker.jar |grep miner\/Tracker -rw-r--r-- 0 0 0 2175 Apr 14 20:38 miner/TrackerUtil.class -rw-r--r-- 0 0 0 40963 Apr 14 20:38 miner/Tracker.class
您的清单文件可能有问题。不过,我不认为这与非数字版本有关。我试过了,它有效。
我确实注意到的是,如果您添加的行包含的空间超过了普通空格(字符 32 dec,20 hex),您将看到您描述的错误,仅仅是因为无法解析清单。MyKey: MyValue显然,清单解析器期望在每个非空行上都有类似的东西。即使在末尾以外的任何地方的空行也可能导致相同的问题,如果它们位于所谓的部分的中间。因此,如果您有以下清单之一,ClassNotFoundException无论您使用-cpor ,您都会看到 a -jar:
MyKey: MyValue
ClassNotFoundException
Manifest-Version: 1.0 Main-Class: miner.Tracker x Manifest-Version: 1.0 Main-Class: miner.Tracker
即使在最后一行之后有一行只包含这样的制表符,也会发生错误:
Manifest-Version: 1.0 Main-Class: miner.Tracker
如果您有使用其他不可见字符(例如非标准Unicode 空格)的行,情况也是如此。
就像我在之前的评论中所说的那样:检查清单中任何地方的此类字符。如果这没有产生任何结果,请检查您的 Java 源代码文件,尤其是包名和类名。
更新:这是一个小的 Java 示例,展示了我之前解释的内容:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.jar.Manifest; public class ManifestValidator { public static void main(String[] args) { // Valid: nothing unusual parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Tracker\n"); // Valid: trailing empty line parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Tracker\n\n"); // Valid: line continuation by leading space parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Track\n er\n"); // Valid: last line is ignored if it does not end with a line feed parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Tracker\nSome garbage"); // Invalid: line beginning with tab parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Tracker\n\t\n"); // Invalid: not a key-value pair "key: value" parseManifest("Manifest-Version: 1.0\nMain-Class: miner.Tracker\nFoo=bar\n"); // Invalid: empty line in section parseManifest("Manifest-Version: 1.0\n\nMain-Class: miner.Tracker\n"); // Invalid: non-default unicode space instead of normal one parseManifest("Manifest-Version: 1.0\nMain-Class:\u00A0miner.Tracker\n"); } public static void parseManifest(String content) { try { Manifest manifest = new Manifest(new ByteArrayInputStream(content.getBytes())); System.out.println(manifest.getMainAttributes().entrySet()); } catch (IOException e) { System.out.println(e); } } } [Manifest-Version=1.0, Main-Class=miner.Tracker] [Manifest-Version=1.0, Main-Class=miner.Tracker] [Manifest-Version=1.0, Main-Class=miner.Tracker] [Manifest-Version=1.0, Main-Class=miner.Tracker] java.io.IOException: invalid header field java.io.IOException: invalid header field java.io.IOException: invalid manifest format java.io.IOException: invalid header field