簡體   English   中英

Java類存在於類路徑中,但啟動失敗並出現錯誤:找不到或加載主類

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

我有一個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嗎?

問題確實是接口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
$

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM