Java类存在于类路径中,但启动失败,错误:无法找到或加载主类 [英] Java class is present in classpath but startup fails with Error: Could not find or load main class

查看:230
本文介绍了Java类存在于类路径中,但启动失败,错误:无法找到或加载主类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个jar文件 foobar.jar 包含以下两个类:

I have a jar file foobar.jar containing the following two classes:

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

如果我使用以下命令执行程序,程序按预期运行并打印 Foo

If I execute the program using the following command, the program behaves as expected and prints Foo:

$ java -cp foobar.jar Foo
Foo
$ 

但如果我尝试启动程序使用类 Bar 中的main方法,JVM打印一个启动错误并退出:

But if I try to start the program using the main method in the class Bar, the JVM prints a startup error and exits:

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

这是同样的错误,就像我尝试使用不在jar中的类启动程序一样,例如

This is the same error as if I would try to start the program using a class which is not in the jar, e.g.

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

为什么会出现此错误?可以启动 Foo.main 方法的事实,我可以从jar中反编译 Bar 类证明,类应该在类路径上可用。我意识到这可能与接口 ItemProcessor 没有在类路径上有关。但在这种情况下我不应该得到 java.lang.ClassNotFoundException 吗?

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. I realize that this could have something to do with the interface ItemProcessor not being on the classpath. But shouldn't I get a java.lang.ClassNotFoundException in that case?

推荐答案

问题确实是接口 ItemProcessor 不在类路径上。请注意,错误指出查找加载主类。在 BarNotThere 的情况下,JVM实际上无法查找主类。但是在 Bar 的情况下,它无法加载主类。

The problem is indeed that the interface ItemProcessor is not on the classpath. 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. But in the Bar case, it is not able to load the main class.

为了完全加载类,JVM还需要每个超类对象的实例。在 Bar 的此过程中,JVM尝试加载 ItemProcessor 的类对象。但由于此接口不在类路径上,因此加载主类 Bar 失败,启动以终止错误:无法找到或加载主class Bar

In order to completely load a class, the JVM also need instances of each superclass objects. During this process for Bar, the JVM tries to load the class object for 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.

如果你很难找到有问题的类(因为没有消息说这样),你可以使用 jdeps 检查类路径的工具。只需使用相同的类路径,但运行 jdeps 而不是 java

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. Just use the same classpath, but run jdeps instead of 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版本)

这应该为您提供足够的提示,以查找缺少的类。

This should give you enough hints as where to look for the missing class.

进一步说明

注意加载之间的区别并初始化一个类。如果在初始化期间类加载失败(这意味着该类已成功找到已加载),您将获得预期的 ClassNotFoundException 。请参阅以下示例:

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

在这种情况下,班级 FooBar 可以在启动期间加载。但它无法初始化,因为静态字段 i 需要 ItemProcessor 类,该类不在类路径中。如果在类上执行静态方法,则初始化是一个前提条件,当JVM尝试调用 main 方法时。

In this case, the class FooBar can be loaded during startup. But it can not be initialized, since the static field i needs the ItemProcessor class, which is not on the classpath. 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.

$ 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
$

这篇关于Java类存在于类路径中,但启动失败,错误:无法找到或加载主类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆