我有一个包含以下两个类的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
:
$ java -cp foobar.jar Foo
Foo
$
但是如果我尝试使用类Bar
中的main方法启动程序,JVM会输出启动错误并退出:
$ 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
方法并且我能够从jar中反编译类Bar
的事实证明,类应该在类路径上可用。我意识到这可能与接口ItemProcessor
不在类路径上有关。但在这种情况下,我不应该得到java.lang.ClassNotFoundException
吗?
答案 0 :(得分:7)
问题确实是接口ItemProcessor
不在类路径上。请注意,错误表示" 查找或加载主类"。在BarNotThere
的情况下,JVM实际上无法查找主类。但在Bar
案例中,它无法加载主要类。
为了完全加载一个类,JVM还需要每个超类对象的实例。在Bar
的此过程中,JVM尝试加载ItemProcessor
的类对象。但由于此接口不在类路径上,因此加载主类Bar
失败,启动终止于Error: Could not find or load main class Bar
。
如果你很难找到有问题的类(因为没有这样的消息),你可以使用jdeps
工具来检查类路径。只需使用相同的类路径,但运行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
。请参阅以下示例:
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
方法时就是这种情况。
$ 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
$