Java class is present in classpath but startup fails with Error: Could not find or load main class
Java class is present in classpath but startup fails with Error: Could not find or load main class
我有一个 jar 文件 foobar.jar
包含以下两个 classes:
public class Foo {
public static void main(String[] args) {
System.out.println("Foo");
}
}
另一个 class 看起来像这样:
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
$
但是如果我尝试使用 class Bar
中的 main 方法启动程序,JVM 会打印启动错误并退出:
$ java -cp foobar.jar Bar
Error: Could not find or load main class Bar
$
这与我尝试使用不在 jar 中的 class 启动程序时的错误相同,例如
$ java -cp foobar.jar BarNotThere
Error: Could not find or load main class BarNotThere
$
为什么会出现此错误? Foo.main
方法可以启动并且我能够从 jar 中反编译 class Bar
的事实证明,class 应该在 class路径。我意识到这可能与接口 ItemProcessor
不在 class 路径上有关。但是在那种情况下我不应该得到一个 java.lang.ClassNotFoundException
吗?
问题确实是接口 ItemProcessor
不在 class 路径上。请注意,错误状态为“find 或 load main class”。在 BarNotThere
的情况下,JVM 确实无法 找到 主要 class。但是在 Bar
的情况下,它无法 load main class.
为了完全加载一个class,JVM还需要每个superclass对象的实例。在 Bar
的这个过程中,JVM 尝试加载 ItemProcessor
的 class 对象。但是由于此接口不在 class 路径上,主 class Bar
的加载失败并且启动以 Error: Could not find or load main class Bar
.
终止
如果您难以找到有问题的 class(因为没有消息这么说),您可以使用 jdeps
工具检查 class 路径。只需使用相同的 class 路径,但 运行 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版本而有很大差异)
这应该会给您足够的提示,告诉您在哪里寻找丢失的 class。
进一步说明
注意加载和初始化 class 之间的区别。如果 classloading 在初始化过程中失败(这意味着 class 已成功 found 和 loaded),你将得到你的预计 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");
}
}
在这种情况下,class FooBar
可以在启动时加载。但它无法初始化,因为静态字段 i
需要 ItemProcessor
class,它不在 class 路径上。如果执行 class 上的静态方法,则初始化是先决条件,当 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
$
我有一个 jar 文件 foobar.jar
包含以下两个 classes:
public class Foo {
public static void main(String[] args) {
System.out.println("Foo");
}
}
另一个 class 看起来像这样:
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
$
但是如果我尝试使用 class Bar
中的 main 方法启动程序,JVM 会打印启动错误并退出:
$ java -cp foobar.jar Bar
Error: Could not find or load main class Bar
$
这与我尝试使用不在 jar 中的 class 启动程序时的错误相同,例如
$ java -cp foobar.jar BarNotThere
Error: Could not find or load main class BarNotThere
$
为什么会出现此错误? Foo.main
方法可以启动并且我能够从 jar 中反编译 class Bar
的事实证明,class 应该在 class路径。我意识到这可能与接口 ItemProcessor
不在 class 路径上有关。但是在那种情况下我不应该得到一个 java.lang.ClassNotFoundException
吗?
问题确实是接口 ItemProcessor
不在 class 路径上。请注意,错误状态为“find 或 load main class”。在 BarNotThere
的情况下,JVM 确实无法 找到 主要 class。但是在 Bar
的情况下,它无法 load main class.
为了完全加载一个class,JVM还需要每个superclass对象的实例。在 Bar
的这个过程中,JVM 尝试加载 ItemProcessor
的 class 对象。但是由于此接口不在 class 路径上,主 class Bar
的加载失败并且启动以 Error: Could not find or load main class Bar
.
如果您难以找到有问题的 class(因为没有消息这么说),您可以使用 jdeps
工具检查 class 路径。只需使用相同的 class 路径,但 运行 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版本而有很大差异)
这应该会给您足够的提示,告诉您在哪里寻找丢失的 class。
进一步说明
注意加载和初始化 class 之间的区别。如果 classloading 在初始化过程中失败(这意味着 class 已成功 found 和 loaded),你将得到你的预计 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");
}
}
在这种情况下,class FooBar
可以在启动时加载。但它无法初始化,因为静态字段 i
需要 ItemProcessor
class,它不在 class 路径上。如果执行 class 上的静态方法,则初始化是先决条件,当 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
$