【问题标题】:Java class is present in classpath but startup fails with Error: Could not find or load main classJava 类存在于类路径中,但启动失败并出现错误:无法找到或加载主类
【发布时间】:2025-12-13 11:00:01
【问题描述】:

我有一个 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 吗?

【问题讨论】:

  • 请注意*.com/questions/18093928/… 部分解决了这个问题。我遇到了这个问题,并试图用所说的问题来解决它。但起初我无法解决它,因为超类不在类路径上的问题是一种边缘情况。这就是我将这个特殊案例添加为新 Q/A 的原因。

标签: java jvm classpath classnotfoundexception classloading


【解决方案1】:

问题确实是接口ItemProcessor不在类路径上。请注意,错误状态为“find or load main class”。在BarNotThere 的情况下,JVM 确实无法find 主类。但在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
$

【讨论】:

  • 但是当Error: Could not find or load main class Bar 发生时,我怎么知道哪个类不在类路径中呢?
  • @zczhuohuo 您可以使用jdeps 工具来分析类路径。我会把这个添加到答案中。
最近更新 更多