简体   繁体   English

Java类存在于类路径中,但启动失败并出现错误:找不到或加载主类

[英]Java class is present in classpath but startup fails with Error: Could not find or load main class

I have a jar file foobar.jar containing the following two classes: 我有一个jar文件foobar.jar其中包含以下两个类:

public class Foo {

    public static void main(String[] args) {
        System.out.println("Foo");
    }
}

The other class looks like this: 另一个类如下所示:

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;
    }
}

If I execute the program using the following command, the program behaves as expected and prints Foo : 如果我使用以下命令执行该程序,则该程序将按预期方式运行并显示Foo

$ java -cp foobar.jar Foo
Foo
$ 

But if I try to start the program using the main method in the class Bar , the JVM prints a startup error and exits: 但是,如果我尝试使用Bar类中的main方法来启动程序,则JVM将显示启动错误并退出:

$ java -cp foobar.jar Bar
Error: Could not find or load main class Bar
$

This is the same error as if I would try to start the program using a class which is not in the jar, eg 这与我尝试使用不在jar中的类来尝试启动程序的错误相同,例如

$ java -cp foobar.jar BarNotThere
Error: Could not find or load main class BarNotThere
$

Why do I get this error? 为什么会出现此错误? The fact that the Foo.main method can be started and I'm able to decompile the class Bar from the jar proves, that the class should be available on the classpath. Foo.main方法可以启动并且我可以从jar中反编译Bar类这一事实证明,该类应该在类路径上可用。 I realize that this could have something to do with the interface ItemProcessor not being on the classpath. 我意识到这可能与ItemProcessor接口不在类路径上有关。 But shouldn't I get a java.lang.ClassNotFoundException in that case? 但是在那种情况下我不应该得到java.lang.ClassNotFoundException吗?

The problem is indeed that the interface ItemProcessor is not on the classpath. 问题确实是接口ItemProcessor不在类路径上。 Notice that the error states " find or load main class". 请注意,错误状态为“ 查找加载主类”。 In the case of BarNotThere the JVM is really not able to find the main class. BarNotThere的情况下,JVM确实无法找到主类。 But in the Bar case, it is not able to load the main class. 但是在Bar情况下,它无法加载主类。

In order to completely load a class, the JVM also need instances of each superclass objects. 为了完全加载类,JVM还需要每个超类对象的实例。 During this process for Bar , the JVM tries to load the class object for ItemProcessor . Bar此过程中,JVM尝试加载ItemProcessor的类对象。 But since this interface is not on the classpath, loading of the main class Bar fails and the startup terminates with the Error: Could not find or load main class Bar . 但是,因为此接口不在类路径上,所以主类Bar加载失败,并且启动因Error: Could not find or load main class Bar终止。

If you struggle with finding the problematic class in question (because the is no message saying so), you can use the jdeps tool to inspect the classpath. 如果您在寻找有问题的类时遇到困难(因为没有消息这样说),则可以使用jdeps工具检查类路径。 Just use the same classpath, but run jdeps instead of 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

(This was created using openjdk-9, actual output may vary heavily depending on the Java version) (这是使用openjdk-9创建的,实际输出可能会有所不同,具体取决于Java版本)

This should give you enough hints as where to look for the missing class. 这应该为您提供足够的提示,以指示在哪里寻找缺失的班级。


Further explanation 进一步说明

Notice the difference between loading and initializing a class. 注意加载和初始化类之间的区别。 If classloading fails during initialization (which means the class was successfully found and loaded ), you will get your expected ClassNotFoundException . 如果初始化期间类加载失败(这意味着已成功找到加载该类),则将获得预期的ClassNotFoundException See the following example: 请参见以下示例:

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");
    }
}

In this case, the class FooBar can be loaded during startup. 在这种情况下,可以在启动期间加载FooBar类。 But it can not be initialized, since the static field i needs the ItemProcessor class, which is not on the classpath. 但是它无法初始化,因为静态字段i需要ItemProcessor类,该类不在类路径中。 Initialization is a precondition if a static method on a class is executed, which is the case, when the JVM tries to invoke the main method. 如果在类上执行静态方法,则初始化是前提条件,在这种情况下,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
$

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM