我有一个foobar.jar包含以下两个类的 jar 文件:
foobar.jar
public class Foo { public static void main(String[] args) { System.out.println("Foo"); } }
另一个类如下所示:
import javax.batch.api.chunk.ItemProcessor; public class Bar implements ItemProcessor { public static void main(String[] args) { System.out.println("Bar"); } @Override public Object processItem(Object item) throws Exception { return item; } }
如果我使用以下命令执行程序,程序将按预期运行并打印Foo:
Foo
$ java -cp foobar.jar Foo Foo $
但是如果我尝试使用类中的 main 方法启动程序Bar,JVM 会打印一个启动错误并退出:
Bar
$ java -cp foobar.jar Bar Error: Could not find or load main class Bar $
这与我尝试使用不在 jar 中的类启动程序相同的错误,例如
$ java -cp foobar.jar BarNotThere Error: Could not find or load main class BarNotThere $
为什么我会收到此错误?该Foo.main方法可以启动并且我能够Bar从 jar 中反编译该类的事实证明,该类应该在类路径上可用。我意识到这可能与接口ItemProcessor不在类路径上有关。java.lang.ClassNotFoundException但在那种情况下我不应该得到一个吗?
Foo.main
ItemProcessor
java.lang.ClassNotFoundException
问题确实是接口ItemProcessor不在类路径上。请注意,错误状态为“查找或加载主类”。在JVM的情况下BarNotThere是真的找不到主类。但在这种Bar情况下,它无法加载主类。
BarNotThere
为了完全加载一个类,JVM还需要每个超类对象的实例。在这个过程中Bar,JVM 尝试为 加载类对象ItemProcessor。但是由于这个接口不在类路径上,主类的加载Bar失败并且启动以Error: Could not find or load main class Bar.
Error: Could not find or load main class Bar
如果您很难找到有问题的类(因为没有消息这么说),您可以使用该jdeps工具检查类路径。只需使用相同的类路径,但运行jdeps而不是java:
jdeps
java
$ jdeps -cp foobar.jar Bar foobar.jar -> java.base foobar.jar -> not found <unnamed> (foobar.jar) -> java.io -> java.lang -> javax.batch.api.chunk not found
(这是使用 openjdk-9 创建的,实际输出可能因 Java 版本而有很大差异)
这应该会给你足够的提示,告诉你在哪里寻找缺失的课程。
进一步说明
注意加载和初始化类之间的区别。如果在初始化期间类加载失败(这意味着类已成功找到并加载),您将获得预期的ClassNotFoundException. 请参见以下示例:
ClassNotFoundException
import javax.batch.api.chunk.ItemProcessor; public class FooBar { private static ItemProcessor i = new ItemProcessor() { @Override public Object processItem(Object item) throws Exception { return item; } }; public static void main(String[] args) { System.out.println("Foo"); } }
在这种情况下,FooBar可以在启动期间加载该类。但它不能被初始化,因为静态字段i需要ItemProcessor类,它不在类路径上。如果一个类的静态方法被执行,那么初始化是一个先决条件,当 JVM 试图调用该main方法时就是这种情况。
FooBar
i
main
$ java -cp foobar.jar FooBar Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.NoClassDefFoundError: javax/batch/api/chunk/ItemProcessor at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) at java.lang.Class.privateGetMethodRecursive(Class.java:3048) at java.lang.Class.getMethod0(Class.java:3018) at java.lang.Class.getMethod(Class.java:1784) at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526) Caused by: java.lang.ClassNotFoundException: javax.batch.api.chunk.ItemProcessor at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 7 more $