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


530

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


1
Я верю, что это также может произойти, если вы не запустите свою Java-программу с правильным синтаксисом. Например, вы должны вызвать ваш класс из корневой папки bin с полным именем пакета (т.е. my.package.myClass). Я был бы более конкретным, если бы мог, но я не очень хороший парень из Java. Я просто помню, как испортил это несколько раз.
Фрэнк Гаддер

17
@BoltClock Нам нужен канонический вопрос, чтобы указать на многочисленные дубликаты. Почему этого не может быть?
Raedwald

21
Рассматривали ли вы вопрос об изменении принятого ответа, чтобы тот, который сообщество считает более ценным, оказался на вершине?
Мартин Смит

Ответы:


264

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


1
Эта ошибка произошла, когда я поместил исходный файл в неправильное пространство имен / пакет. Я подумал, что могу просто положить его куда угодно, и компилятор был счастлив. Оказывается, я должен был быть более усердным во время выполнения, чтобы быть счастливым.
ЦентрОрбит

1
У меня была одна ошибка, когда мой сервер исчерпал память во время загрузки файла. Каждый раз, когда я пытался загрузить, я получал разные ошибки. В конце концов мне сказали, что у меня недостаточно места в куче.
Джеймс М. Лей

81
Этот ответ не обязательно верен и вводит в заблуждение многих людей! Смотрите лучший ответ от Джареда ниже.
Дейв Л.

4
@DaveL. Спасибо! Ответ Джареда с более чем 400 ответами ниже! Один ответ с -4 повышением (понижением?) Голосов намного выше этого. В логике упорядочения ответов SO есть что-то подозрительное.
Саураб Патил

1
Для кого-то это длинный путь, но я столкнулся с этой ошибкой, потому что рассматриваемый класс содержал SimpleDateFormat, который был инициализирован с недопустимым символом (у меня было T в середине вместо 'T').
Райан Д

819

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

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

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

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


30
Спасибо за упоминание причины NoClassDefFoundError, это мне очень помогло! В моем случае ExceptionInInitializerError был брошен ранее, вот как я узнал об ошибках в статических блоках.
Томас

@Jared, когда я получу, Error: Could not find or load main classэто будет классифицировано под какой категорией ошибок?
Викрам

@Pops: язык стал более многословным, чтобы определять объекты глаголов «попробуй» :)
Джаред

1
@Vikram «Не удалось найти или загрузить основной класс» не является исключением Java, оно вызывается модулем запуска (который проверяет JAR и атрибут основного манифеста).
Eckes

2
ClassNotFoundException также генерируется, когда класс имеет статическую инициализацию, которая выдает ошибку или исключение. Возможно, им следовало выбрать другое название для этого события.
coladict

125

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

3
И причина в том, что после первой попытки jvm уже знает, что он не будет работать, и выдает другое исключение во второй раз?
ikamen

@ikamen Видимо, где-то хранилась неудачная инициализация класса SimpleCalculatorпосле деления на ноль? У кого-нибудь есть ссылка на официальную документацию по этому поведению?
ᴠɪɴᴄᴇɴᴛ

4
@PhilipRego Не уверен, что вы подразумеваете под «чистым» NoClassDefFoundError. При первом new SimpleCalculator()вызове вы получаете ExceptionInInitializerError с вызванной ArithmeticException. Во второй раз вы вызываете new SimpleCalculator()NoClassDefFoundError так же чисто, как и любой другой. Дело в том, что вы можете получить NoClassDefFoundError по причине, отличной от SimpleCalculator.class, отсутствующей в пути к классам во время выполнения.
Harperska

36

NoClassDefFoundError в Java

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

  1. Виртуальная машина Java не может найти определенный класс во время выполнения, который был доступен во время компиляции.

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

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

Примеры:

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

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

  4. Проблема с правами доступа к файлу JAR также может вызвать NoClassDefFoundError в Java.
  5. Опечатка в конфигурации XML также может вызвать NoClassDefFoundError в Java.
  6. когда ваш скомпилированный класс, который определен в пакете, не присутствует в том же пакете во время загрузки, как в случае с JApplet, он выдаст NoClassDefFoundError в Java.

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

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

Ресурсы:

3 способа решить NoClassDefFoundError

java.lang.NoClassDefFoundError Образцы проблем


1
Отличный ответ. Я думаю, что перепробовал все, что вы предлагаете, и все еще имею эту проблему. Я могу исключить некоторые из них из-за работы jar с пружиной, но java.sql, похоже, не нравится (в моем случае драйвер sap db для Hana).
Картер II

На самом деле он называется System.getproperty ("java.class.path")
RIJIK

33

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

set classpath=%classpath%;axis.jar

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

set classpath=axis.jar;%classpath%;

4
Была такая же проблема. Оказывается, я скомпилировал файл war с Java7, но моя установка Tomcat была на Java6. Я должен был обновить свои переменные среды
duvo

4
Если это произойдет, я скажу, что Java в беспорядке. +2 если это правда. Пока не могу проверить это. Если найдено значение true, снова будет + 1 (в комментариях)
сверхновая

7

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

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

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

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

Структура файла будет выглядеть так: введите описание изображения здесь

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


6

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

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

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

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


1
То же самое произошло со мной при программировании сервлета (на NoClassDefFoundErrorсамом деле это было вызвано тем ExceptionInInitalizerError, что было вызвано DateTimeParseException). Это немного вводит в заблуждение, не так ли? Я знаю, что у них, вероятно, были свои причины сделать это, но было бы так приятно иметь хотя бы небольшой намек, который NoClassDefFoundErrorбыл результатом другого исключения, без необходимости выводить его. Просто бросить ExceptionInInitializerErrorснова было бы намного яснее. Иногда связь между ними может быть не столь очевидной.
Бартломей Зелиньски

5

Я получаю 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;
            }
        });
    }
}

1
Ссылка мертва. Попробуйте архивную версию: web.archive.org/web/20131216000019/https://blogs.oracle.com/…
avgvstvs

5

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

  1. throwRuntimeExceptionв 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будет брошен в сопровождении ExceptionInInitializerErrorот статического блока RuntimeException.


Это особенно важно в тех случаях, когда вы видите NoClassDefFoundErrorsв своих ЕДИНИЦАХ ИСПЫТАНИЯ .

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


4
Это чертовски полезный совет в реальной жизни. У меня была такая же ситуация с инициализаторами атрибутов класса. У вас есть только один шанс увидеть актуальную проблему в журнале. Как только класс загружен (или попытался в любом случае), вам нужно все перезапустить.
DailyFrankPeter

4

Методика ниже помогла мне много раз:

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

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


3

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

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


"ЭДС" ? Вы имеете в виду " MEF " ?
Питер Мортенсен

2
Нет. EMf как Eclipse Modeling Framework. В автомобильной промышленности мы можем столкнуться с этой ошибкой при запуске сгенерированного кода.
Aykut Kllic

1

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

dexOptions {
        preDexLibraries false
        ...

1

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

Это неверно Отсутствующий ресурс не даст вам этой ошибки. Вы получите его, только если класс отсутствует.
Стивен С.

@StephenC Может быть, я должен подчеркнуть эту часть больше, но я написал for example a properties file that the affected class tries to load from the META-INF directory. Это на самом деле произошло со мной, и я смог решить NoClassDefFoundError, добавив отсутствующий файл свойств. Я добавил этот ответ именно потому, что никто не ожидал этой ошибки при указанных обстоятельствах.
ᴠɪɴᴄᴇɴᴛ

1
Тогда вы упустили что-то очень важное в своем объяснении, потому что единственный способ, которым отсутствующий файл ресурсов может вызвать это исключение, - это если вы пытаетесь загрузить файл ресурсов в процессе staticинициализации ... который вызвал непроверенное исключение и вызвал класс init терпеть неудачу. Любое непроверенное исключение, распространяющееся из статической инициализации, сделает это.
Стивен С.

Если я ошибаюсь (то есть это происходит не из-за неудачной staticинициализации), мне было бы интересно увидеть реальный пример (т.е. MCVE), который демонстрирует поведение.
Стивен С.

1
@StephenC Вы абсолютно правы, хотя :( Я посмотрел случай, когда я столкнулся с этой проблемой, и она действительно включала статический инициализатор, пытающийся загрузить пакет ресурсов. Я дополню / исправлю свое описание причины. Спасибо за указание этого вне.
ᴠɪɴᴄᴇɴᴛ

1

Я получил эту ошибку, когда я добавил Maven-зависимость другого модуля в свой проект, и проблема была окончательно решена путем добавления -Xss2mопции JVM в моей программе (по умолчанию это один мегабайт, начиная с JDK5.0). Считается, что программе не хватает стека для загрузки класса.


0

Если кто-то приходит сюда из-за java.lang.NoClassDefFoundError: org/apache/log4j/Loggerошибки, в моем случае она возникла потому, что я использовал log4j 2 (но я не добавил все файлы, которые идут с ним), а некоторая библиотека зависимостей использовала log4j 1. Решением было добавить Log4j. 1.x bridge: jar, log4j-1.2-api-<version>.jarкоторый поставляется с log4j 2. Больше информации в log4j 2 миграции .


0

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

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

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


0

Эта ошибка может быть вызвана непроверенными требованиями к версии Java .

В моем случае мне удалось устранить эту ошибку при создании громкого проекта с открытым исходным кодом, переключившись с Java 9 на Java 8 с помощью SDKMAN! ,

sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu

Затем выполните чистую установку, как описано ниже.


При использовании Maven в качестве инструмента сборки иногда полезно - и, как правило, приятно, делать чистую сборку «install» с отключенным тестированием .

mvn clean install -DskipTests

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

mvn test

0

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


0

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


0

В моем случае я получал эту ошибку из-за несоответствия версий JDK. Когда я пытался запустить приложение из Intelij, оно не работало, но потом работало его из командной строки. Это связано с тем, что Intelij пытался запустить его с установленным Java 11 JDK, но в командной строке он работал с Java 8 JDK. После переключения этого параметра в меню «Файл»> «Структура проекта»> «Параметры проекта»> «Project SDK» он сработал.


0

Все говорят здесь о некоторой конфигурации Java, проблемах JVM и т. Д., В моем случае ошибка вообще не была связана с этими темами и имела очень тривиальную и легко решаемую причину: у меня была неправильная аннотация на моей конечной точке в контроллере ( Приложение Spring Boot).


0

У меня была интересная проблема с NoClassDefFoundError в JavaEE при работе с сервером Liberty. Я использовал адаптеры ресурсов IMS, и в моем server.xml уже был адаптер ресурсов для imsudbJXA.rar. Когда я добавил новый адаптер для imsudbXA.rar, я начал получать эту ошибку для объектов экземпляра для DLIException, IMSConnectionSpec или SQLInteractionSpec. Я не мог понять, почему, но я решил это, создав новый файл server.xml для своей работы, используя только imsudbXA.rar. Я уверен, что использование нескольких ресурсных адаптеров в server.xml - это нормально, у меня просто не было времени на это разбираться.


-1

Java не смог найти класс A во время выполнения. Класс А был в Maven проекте ArtClient из другого рабочего пространства. Поэтому я импортировал ArtClient в свой проект Eclipse. Два моих проекта использовали ArtClient в качестве зависимости. Я изменил ссылку на библиотеку на ссылку проекта для этих (Build Path -> Configure Build Path).

И проблема ушла.


-1

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

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

Например,

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

-6

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

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


4
Это объясняется ответом с наибольшим количеством голосов: когда вы сначала скомпилировали, файлы были там, затем вы удалили некоторые файлы, классы были удалены, поэтому во время выполнения вы получили ClassNotFound, а затем вернули их обратно, но Eclipse все еще не обратите внимание, что сгенерированные классы по-прежнему отсутствуют, но после перезапуска Eclipse рабочая область была обновлена, и классы снова стали доступны, но в целом это не решение или обходной путь, решение состоит в том, чтобы найти, какой класс / jar отсутствует во время выполнения CLASSPATH.
Хосе Мануэль Гомес Альварес

-7

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

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

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

3
Насколько ваше решение каким-либо образом относится к этой общей проблеме?
Таави Ильвес

Пример конфигурации не сбалансирован (три {sи два }). Ты можешь починить это?
Питер Мортенсен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.