Класс Java присутствует в classpath, но запуск завершается неудачно с ошибкой: не удалось найти или загрузить основной класс
У меня есть фляга 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
, JVM печатает ошибку запуска и завершает работу:
$ java -cp foobar.jar Bar
Error: Could not find or load main class Bar
$
Это та же ошибка, что если бы я попытался запустить программу, используя класс, которого нет в банке, например
$ java -cp foobar.jar BarNotThere
Error: Could not find or load main class BarNotThere
$
Почему я получаю эту ошибку? Тот факт, что Foo.main
метод может быть запущен, и я могу декомпилировать класс Bar
из банки доказывает, что класс должен быть доступен на пути к классам. Я понимаю, что это может быть связано с интерфейсом ItemProcessor
не быть на пути к классам. Но я не должен получить java.lang.ClassNotFoundException
в таком случае?
1 ответ
Проблема действительно в том, что интерфейс 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
$