Почему я получаю NoClassDefFoundError в Java?
-
09-06-2019 - |
Вопрос
Я получаю NoClassDefFoundError
когда я запускаю свое Java-приложение.Что обычно является причиной этого?
Решение
Это происходит, когда существует файл класса, от которого зависит ваш код, и он присутствует во время компиляции, но не найден во время выполнения. Ищите различия во времени сборки и во время выполнения классов. Р>
Другие советы
Хотя возможно, что это связано с несоответствием пути к классам между временем компиляции и временем выполнения, это не всегда так.
В этом случае важно держать два или три разных исключения в нашей голове:
<Ол> java.lang.ClassNotFoundException
Это исключение означает, что класс не найден в пути к классам. Это указывает на то, что мы пытались загрузить определение класса, а класс не существовал в пути к классам.
java.lang.NoClassDefFoundError
. Это исключение означает, что JVM проверила в своей внутренней структуре данных определения класса определение класса и не нашла его. Это отличается от того, что он не может быть загружен из пути к классам. Обычно это указывает на то, что мы ранее пытались загрузить класс из пути к классам, но по какой-то причине это не удалось - теперь мы пытаемся использовать класс снова (и, следовательно, нужно загрузить его, так как в прошлый раз он не удался), но мы ' мы даже не собираемся пытаться загрузить его, потому что мы не смогли загрузить его раньше (и разумно подозреваем, что у нас снова получится ошибка). Более ранний сбой мог быть ClassNotFoundException или ExceptionInInitializerError (указывающий на сбой в блоке статической инициализации) или любым другим количеством проблем. Дело в том, что NoClassDefFoundError не обязательно является проблемой пути к классам.
Вот код для иллюстрации java.lang.NoClassDefFoundError
. См. ответ Джареда для подробного объяснения.
NoClassDefFoundErrorDemo.java
public class NoClassDefFoundErrorDemo {
public static void main(String[] args) {
try {
// The following line would throw ExceptionInInitializerError
SimpleCalculator calculator1 = new SimpleCalculator();
} catch (Throwable t) {
System.out.println(t);
}
// The following line would cause NoClassDefFoundError
SimpleCalculator calculator2 = new SimpleCalculator();
}
}
SimpleCalculator.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
Я обнаружил, что иногда я получаю ошибку NoClassDefFound, когда код компилируется с несовместимой версией класса, найденной во время выполнения. Конкретный экземпляр, который я помню, связан с библиотекой оси Apache. На моем пути к классам во время выполнения на самом деле было две версии, и он выбирал устаревшую и несовместимую версию, а не правильную, вызывая ошибку NoClassDefFound. Это было в приложении командной строки, где я использовал команду, подобную этой. Р>
set classpath=%classpath%;axis.jar
Мне удалось заставить его подобрать правильную версию с помощью:
set classpath=axis.jar;%classpath%;
NoClassDefFoundError В Java
Определение:
Виртуальная машина Java не может найти конкретный класс во время выполнения, который был доступен во время компиляции.
Если класс присутствовал во время компиляции, но недоступен в java classpath во время выполнения.
Примеры:
- Класс не находится в Classpath, нет надежного способа узнать это, но часто вы можете просто взглянуть на print System.getproperty("java.classpath"), и он напечатает путь к классу, оттуда вы можете, по крайней мере, получить представление о вашем фактическом пути к классу во время выполнения.
Простой пример NoClassDefFoundError - класс принадлежит отсутствующему файлу JAR, или JAR не был добавлен в classpath, или иногда имя jar было кем-то изменено, как в моем случае, один из моих коллег изменил tibco.jar в tibco_v3.jar и программа терпит неудачу с java.lang.NoClassDefFoundError и я задавались вопросом, в чем дело.
Просто попробуйте запустить с параметром явно -classpath с тем classpath, который, по вашему мнению, будет работать, и если он работает, то это верный короткий признак того, что кто-то переопределяет java classpath.
- Проблема с разрешениями для файла JAR также может вызвать NoClassDefFoundError в Java.
- Опечатка в конфигурации XML также может вызвать NoClassDefFoundError в Java.
- когда ваш скомпилированный класс, который определен в пакете, не присутствует в том же пакете при загрузке, как в случае с JApplet, он выдает NoClassDefFoundError в Java.
Возможные решения:
- Этот класс недоступен в Java Classpath.
- Если вы работаете в среде J2EE, то видимость класса среди нескольких загрузчиков классов также может вызвать ошибку java.lang.NoClassDefFoundError, подробное обсуждение см. В разделе примеры и сценарий.
- Проверьте наличие java.lang.ExceptionInInitializerError в вашем файле журнала.Ошибка NoClassDefFoundError из-за сбоя статической инициализации встречается довольно часто.
- Поскольку NoClassDefFoundError является подклассом java.lang.LinkageError, он также может появиться, если одна из его зависимостей, например, собственная библиотека, может быть недоступна.
- Любой запускаемый скрипт переопределяет переменную окружения Classpath.
- Возможно, вы запускаете свою программу с помощью команды jar, а класс не был определен в атрибуте ClassPath файла манифеста.
Ресурсы:
Это и есть тот самый лучшее решение Я нашел до сих пор.
Предположим, у нас есть пакет под названием org.mypackage
содержащий классы:
- HelloWorld (основной класс)
- Класс поддержки
- Класс утилиты
и файлы, определяющие этот пакет, физически хранятся в каталоге D:\myprogram
(в Windows) или /home/user/myprogram
(в Linux).
Файловая структура будет выглядеть следующим образом:
Когда мы вызываем Java, мы указываем имя приложения для запуска: org.mypackage.HelloWorld
.Однако мы также должны указать Java, где искать файлы и каталоги, определяющие наш пакет.Итак, чтобы запустить программу, мы должны использовать следующую команду:
Я использовал Spring Framework с Maven и решил эту ошибку в моем проекте.
В классе произошла ошибка во время выполнения. Я читал свойство как целое число, но когда оно прочитало значение из файла свойств, его значение было двойным.
Spring не дал мне полную трассировку стека, в какой строке произошла ошибка во время выполнения.
Там просто сказано NoClassDefFoundError
. Но когда я выполнил его как собственное Java-приложение (взяв его из MVC), он дал ExceptionInInitializerError
истинную причину и то, как я отследил ошибку.
@ Ответ xli дал мне понимание того, что может быть не так в моем коде.
Я получаю NoClassFoundError, когда классы, загруженные загрузчиком классов среды выполнения, не могут получить доступ к классам, уже загруженным загрузчиком Java. Поскольку разные загрузчики классов находятся в разных доменах безопасности (в соответствии с java), jvm не позволит разрешить классы, уже загруженные корневым загрузчиком, в адресном пространстве загрузчика времени выполнения.
Запустите вашу программу с помощью 'java -javaagent: tracer.jar [ВАШИ java ARGS]'
Он выдает результат, показывающий загруженный класс и загрузчик env, который загрузил класс. Очень полезно отслеживать, почему класс не может быть разрешен.
// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5
import java.lang.instrument.*;
import java.security.*;
// manifest.mf
// Premain-Class: ClassLoadTracer
// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class
// java -javaagent:tracer.jar [...]
public class ClassLoadTracer
{
public static void premain(String agentArgs, Instrumentation inst)
{
final java.io.PrintStream out = System.out;
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);
// dump stack trace of the thread loading class
Thread.dumpStack();
// we just want the original .class bytes to be loaded!
// we are not instrumenting it...
return null;
}
});
}
}
Прочтите это, особенно если вы видите NoClassDefFoundErrors
в МОДУЛЬНЫХ ТЕСТАХ...
Один интересный случай, в котором вы могли бы увидеть много NoClassDefFoundErrors
это когда ты:
throw
aRuntimeException
вstatic
блок вашего классаExample
- Перехватите его (или, если это просто не имеет значения, как будто оно брошено в тестовый пример)
- Попробуйте создать экземпляр этого класса
Example
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
try {
new Example();
} catch (Throwable ignored) { //simulating catching RuntimeException from static block
// DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError
будет выброшен в сопровождении ExceptionInInitializerError
из статического блока RuntimeException
.
Это особенно важный случай, когда вы видите NoClassDefFoundErrors
в вашем МОДУЛЬНЫЕ ТЕСТЫ.
В некотором смысле вы "делитесь" static
блокировать выполнение между тестами, но начальный ExceptionInInitializerError
это будет только в одном тестовом примере.Первый, который использует проблемный Example
класс.Другие тестовые примеры, использующие Example
класс просто выбросит NoClassDefFoundErrors
.
Если вы сгенерировали код (EMF и т. д.), может быть слишком много статических инициализаторов, которые занимают все пространство стека. Р>
См. стек &. Вопрос переполнения Как увеличить размер стека Java? .
Методика, приведенная ниже, помогла мне много раз:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
где TheNoDefFoundClass - это класс, который может быть " lost " из-за предпочтения более старой версии той же библиотеки, используемой вашей программой. Это чаще всего происходит в тех случаях, когда клиентское программное обеспечение развертывается в доминирующем контейнере, оснащенном собственными загрузчиками классов и множеством древних версий самых популярных библиотек.
Я исправил свою проблему, отключив preDexLibraries для всех модулей:
dexOptions {
preDexLibraries false
...
NoClassDefFoundError
также может происходить, когда инициализатор статический пытается загрузить пакет ресурсов, который недоступен во время выполнения, например файл свойств, который уязвимый класс пытается загрузить из META-INF
каталог, но <<>> # 8217; т там нет. Если вы не & # 8217; t ловите catch
, иногда вы выигрываете & # 8217; t не сможете увидеть полную трассировку стека; чтобы преодолеть это, вы можете временно использовать предложение Throwable
для <=>:
try {
// Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}
Если кто-то приходит сюда из-за ошибки java.lang.NoClassDefFoundError: org/apache/log4j/Logger
, в моем случае она возникла потому, что я использовал log4j 2 (но я не добавил все файлы, которые идут с ним), а некоторая библиотека зависимостей использовала log4j 1. Решением было добавить мост Log4j 1.x: jar log4j-1.2-api-<version>.jar
, поставляемый с log4j 2. Дополнительная информация в log4j 2 миграция .
Две разные проверочные копии одного и того же проекта
В моем случае проблема заключалась в неспособности Eclipse различать две разные копии одного и того же проекта. У меня один заблокирован на транке (контроль версий SVN), а другой работает в одной ветви одновременно. Я опробовал одно изменение в рабочей копии как тестовый пример JUnit, который включал в себя извлечение частного внутреннего класса в открытый класс, и пока он работал, я открываю другую копию проекта, чтобы посмотреть на некоторые другие часть кода, которая нуждалась в изменениях. В какой-то момент NoClassDefFoundError
появилась жалоба на то, что частного внутреннего класса там не было; двойной щелчок в трассировке стека привел меня к исходному файлу в неправильной копии проекта.
Закрытие транковой копии проекта и запуск тестового примера снова избавили от проблемы.
Эта ошибка может быть вызвана непроверенными требованиями версии Java .
В моем случае мне удалось устранить эту ошибку при создании громкого проекта с открытым исходным кодом, переключившись с Java 9 на Java 8 с помощью SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Затем выполните чистую установку, как описано ниже.
<Ч>При использовании Maven в качестве инструмента для сборки иногда бывает полезно - и обычно приятно делать чистую «установку» сборки с отключенным тестированием .
mvn clean install -DskipTests
Теперь, когда все собрано и установлено, вы можете продолжить и запустить тесты.
mvn test
Я получил ошибки NoClassDefFound, когда не экспортировал класс в quot; Order and Export " вкладка в Путь сборки Java моего проекта. Обязательно поставьте галочку в & Quot; Заказ и экспорт & Quot; вкладка любых зависимостей, которые вы добавляете в путь сборки проекта. См. Предупреждение об затмении: XXXXXXXXXXX.jar будет не подлежит экспорту или публикации. Могут возникнуть исключения времени выполнения ClassNotFoundExceptions .
Java не удалось найти класс A во время выполнения. Класс А был в Maven проекте ArtClient из другого рабочего пространства. Поэтому я импортировал ArtClient в свой проект Eclipse. Два моих проекта использовали ArtClient в качестве зависимости. Я изменил ссылку на библиотеку на ссылку на проект для этих (Build Path - & Gt; Configure Build Path).
И проблема ушла. Р>
У меня была та же проблема, и я много часов был на складе.
Я нашел решение. В моем случае был определен статический метод. JVM не может создать другой объект этого класса.
Например,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Я получил это сообщение после удаления двух файлов из библиотеки SRC, и когда я возвращал их, я продолжал видеть это сообщение об ошибке.
Мое решение было: перезапустите Eclipse. С тех пор я больше не видел это сообщение: -)
Убедитесь, что это совпадает в module:app
и module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}