Почему я получаю NoClassDefFoundError в Java?

Я получаю NoClassDefFoundError, когда запускаю приложение Java. Что обычно является причиной этого?

Ответы

Ответ 1

Это вызвано тем, что есть файл класса, от которого зависит ваш код, и он присутствует во время компиляции, но не найден во время выполнения. Ищите различия в времени сборки и классах времени выполнения.

Ответ 2

Хотя возможно, что это связано с несоответствием пути к классам между временем компиляции и временем выполнения, это не обязательно верно.

Важно сохранить два или три разных исключения прямо в нашей голове в этом случае:

  • java.lang.ClassNotFoundException Это исключение указывает, что класс не найден в пути к классам. Это указывает на то, что мы пытались загрузить определение класса, и класс не существовал в пути к классам.

  • java.lang.NoClassDefFoundError Это исключение указывает на то, что JVM просмотрел внутреннюю структуру данных определения класса для определения класса и не нашел его. Это отличается от того, что он не может быть загружен из пути к классам. Обычно это указывает на то, что мы ранее пытались загрузить класс из пути к классам, но по какой-то причине он потерпел неудачу - теперь мы снова пытаемся использовать этот класс (и, следовательно, необходимо загрузить его, поскольку он провалился в последний раз) я даже не попытаюсь загрузить его, потому что мы не выполнили его загрузку ранее (и разумно подозреваем, что мы снова потерпим неудачу). Ранним отказом может быть исключение ClassNotFoundException или ExceptionInInitializerError (указывающее на отказ в статическом блоке инициализации) или любое количество других проблем. Дело в том, что NoClassDefFoundError не обязательно является проблемой класса.

Ответ 3

Вот код для иллюстрации 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;
}

Ответ 4

NoClassDefFoundError В Java

Определение:

  • Java Virtual Machine не может найти определенный класс во время выполнения, который был доступен во время компиляции.

  • Если во время компиляции класс присутствовал, но не доступен в java classpath во время выполнения.

введите описание изображения здесь

<сильные > Примеры:

  • Класс не находится в Classpath, нет уверенного способа узнать его, но во многих случаях вы можете просто взглянуть на печать System.getproperty( "java.classpath" ), и он напечатает путь к классам там, где вы можете по крайней мере, получить представление о вашем фактическом пути пути выполнения.
  • Простым примером NoClassDefFoundError является класс, принадлежащий отсутствующему файлу JAR, или JAR не был добавлен в classpath, или иногда имя jar было изменено кем-то, например, в моем случае один из моих коллег изменил tibco.var на tibco_v3.jar и программа не работает с java.lang.NoClassDefFoundError, и мне было интересно, что не так.

  • Просто попробуйте запустить с явно параметром -classpath с классом classpath, который, по вашему мнению, будет работать, и если он работает, то это верный короткий знак того, что кто-то переопределяет путь класса Java.

  • Разрешение на JAR файл также может вызвать NoClassDefFoundError в Java.
  • Typo on XML Configuration также может вызвать NoClassDefFoundError в Java.
  • когда ваш скомпилированный класс, который определен в пакете, не присутствует в одном пакете во время загрузки, как в случае с JApplet, он будет вызывать NoClassDefFoundError в Java.

Возможные решения:

  • Класс недоступен в Java-классе.
  • Если вы работаете в среде J2EE, чем видимость класса среди нескольких Classloader также может вызвать java.lang.NoClassDefFoundError, см. примеры и сценарий для подробного обсуждения.
  • Проверить на java.lang.ExceptionInInitializerError в вашем файле журнала. NoClassDefFoundError из-за сбоя статической инициализации довольно распространен.
  • Поскольку NoClassDefFoundError является подклассом java.lang.LinkageError, он также может появиться, если некоторая его зависимость, например, родная библиотека, недоступна.
  • Любой запуск script переопределяет переменную среды Classpath.
  • Возможно, вы запускаете свою программу, используя команду jar, и класс не был определен в атрибуте ClassPath в файле манифеста.

Ресурсы

3 способа решения NoClassDefFoundError

java.lang.NoClassDefFoundError Проблемные шаблоны

Ответ 5

Я обнаружил, что иногда я получаю ошибку NoClassDefFound, когда код компилируется с несовместимой версией класса, найденного во время выполнения. Конкретный экземпляр, о котором я помню, связан с библиотекой осей apache. Фактически на моем пути к классам среды исполнения было 2 версии, и она собирала устаревшую и несовместимую версию, а не правильную, вызывая ошибку NoClassDefFound. Это было в приложении командной строки, где я использовал команду, подобную этой.

set classpath=%classpath%;axis.jar

Я смог заставить его подобрать подходящую версию, используя:

set classpath=axis.jar;%classpath%;

Ответ 6

Это лучшее решение, которое я нашел до сих пор.

Предположим, у нас есть пакет с именем org.mypackage содержащий классы:

  • HelloWorld (основной класс)
  • SupportClass
  • UtilClass

и файлы, определяющие этот пакет, физически хранятся в каталоге D:\myprogram (в Windows) или /home/user/myprogram (в Linux).

Структура файла будет выглядеть так: enter image description here

Когда мы вызываем Java, мы указываем имя приложения для запуска: org.mypackage.HelloWorld. Однако мы также должны указать Java, где искать файлы и каталоги, определяющие наш пакет. Итак, чтобы запустить программу, мы должны использовать следующую команду: enter image description here

Ответ 7

Я использовал Spring Framework с Maven и решил эту ошибку в своем проекте.

В классе произошла ошибка времени выполнения. Я читал свойство как целое, но когда он считывал значение из файла свойств, его значение было двойным.

Spring не дал мне полную трассировку стека, на которой строка времени выполнения не удалась. Он просто сказал NoClassDefFoundError. Но когда я выполнил его как родное Java-приложение (взяв его из MVC), он дал ExceptionInInitializerError который был истинной причиной, и именно так я отслеживаю ошибку.

Ответ @xli дал мне представление о том, что может быть неправильным в моем коде.

Ответ 8

Я получаю NoClassFoundError, когда классы, загруженные загрузчиком классов времени выполнения, не могут обращаться к классам, уже загруженным корневым загрузчиком java. Поскольку разные загрузчики классов находятся в разных доменах безопасности (в соответствии с java), jvm не разрешит классы, уже загруженные корневым загрузчиком, которые будут разрешены в адресном пространстве загрузчика времени выполнения.

Запустите свою программу с помощью java -javaagent: tracer.jar [YOUR 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;
            }
        });
    }
}

Ответ 9

Один интересный случай, в котором вы можете увидеть много NoClassDefFoundErrors это когда вы:

  1. throw RuntimeException в static блок вашего класса. Example
  2. Перехватить его (или, если это просто не имеет значения, как если бы его бросили в тестовом примере)
  3. Попробуйте создать экземпляр этого класса. 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 будет NoClassDefError вместе с ExceptionInInitializerError из статического блока RuntimeException.


Это особенно важный случай, когда вы видите NoClassDefFoundErrors в ваших UNIT TESTS.

В некотором смысле вы "разделяете" выполнение static блока между тестами, но первоначальный ExceptionInInitializerError будет только в одном тестовом случае. Первый, который использует проблемный класс Example. Другие тестовые случаи, использующие класс Example, просто NoClassDefFoundErrors.

Ответ 10

Если у вас есть сгенерированный код (EMF и т.д.), Может быть слишком много статических инициализаторов, которые потребляют все пространство стека.

См. Вопрос о переполнении стека. Как увеличить размер стека Java? ,

Ответ 11

Техника ниже помогла мне много раз:

System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

где TheNoDefFoundClass - это класс, который может быть "потерян" из-за предпочтения старой версии той же библиотеки, используемой вашей программой. Это чаще всего случается с случаями, когда клиентское программное обеспечение развертывается в доминирующем контейнере, вооружившись его собственными загрузчиками классов и множеством древних версий самых популярных библиотек.

Ответ 12

Я исправил свою проблему, отключив preDexLibraries для всех модулей:

dexOptions {
        preDexLibraries false
        ...

Ответ 13

NoClassDefFoundError также может возникать, когда статический инициализатор пытается загрузить пакет ресурсов, который недоступен во время выполнения, например файл свойств, который уязвимый класс пытается загрузить из каталога META-INF, но его там нет. Если вы не перехватите NoClassDefFoundError, иногда вы не сможете увидеть полную трассировку стека; чтобы преодолеть это, вы можете временно использовать условие catch для 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);
}

Ответ 14

Если кто-то приходит сюда из-за ошибки 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 migration.

Ответ 15

Две разные копии для проверки того же проекта

В моем случае проблема заключалась в неспособности Eclipse различать две разные копии одного и того же проекта. У меня есть одна блокировка на багажнике (контроль версий SVN), а другой - в одной ветки за раз. Я опробовал одно изменение в рабочей копии как тестовый пример JUnit, который включал в себя извлечение частного внутреннего класса для самостоятельного публичного класса, и пока он работал, я открываю другую копию проекта, чтобы посмотреть вокруг на другой часть кода, которая нуждается в изменениях. В какой-то момент NoClassDefFoundError появился, жалуясь, что частного внутреннего класса не было; двойной щелчок в трассировке стека привел меня к исходному файлу в неправильной копии проекта.

Закрытие соединительной копии проекта и запуск тестового примера снова избавилось от проблемы.

Ответ 16

Эта ошибка может быть вызвана неконтролируемыми требованиями к 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

Ответ 17

Я получил ошибки NoClassDefFound, когда не экспортировал класс на вкладке "Порядок и экспорт" в пути сборки Java моего проекта. Обязательно поставьте галочку на вкладке "Заказ и экспорт" всех зависимостей, которые вы добавляете в путь сборки проекта. См. Предупреждение Eclipse: XXXXXXXXXXX.jar не будет экспортирован или опубликован. Runtime ClassNotFoundExceptions может привести.

Ответ 18

Это также может быть связано с тем, что вы копируете файл кода из IDE с определенным именем пакета и хотите попробовать запустить его с помощью терминала. Сначала вам придется удалить имя пакета из кода. Это происходит со мной.

Ответ 19

У меня была та же проблема, и я был запас в течение многих часов.

Я нашел решение. В моем случае из-за этого был установлен статический метод. JVM не может создать другой объект этого класса.

Например,

private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");

Ответ 20

Java не смог найти класс A во время выполнения. Класс A был в проекте Artline из maven из другого рабочего пространства. Поэтому я импортировал ArtClient в проект Eclipse. Два из моих проектов использовали ArtClient в качестве зависимости. Я изменил ссылку на библиотеку для ссылки на проект для этих (Путь сборки → Настроить путь сборки).

И проблема исчезла.

Ответ 21

Я получил это сообщение после удаления двух файлов из библиотеки SRC, и когда я вернул их, я продолжал видеть это сообщение об ошибке.

Моим решением было: Перезапустить Eclipse. С тех пор я еще не видел этого сообщения :-)

Ответ 22

Убедитесь, что это соответствует module:app и module:lib:

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

    defaultConfig {
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 11
        versionName "2.1"
    }