Почему я получаю NoClassDefFoundError в Java? - PullRequest
471 голосов
/ 29 августа 2008

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

Ответы [ 21 ]

722 голосов
/ 22 апреля 2011

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

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

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

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

235 голосов
/ 29 августа 2008

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

103 голосов
/ 13 февраля 2015

Вот код для иллюстрации 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;
}
31 голосов
/ 29 августа 2008

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

set classpath=%classpath%;axis.jar

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

set classpath=axis.jar;%classpath%;
29 голосов
/ 10 августа 2016

NoClassDefFoundError В Java

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

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

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

enter image description here

Примеры:

  1. Класс не находится в Classpath, нет точного способа узнать его, но во многих случаях вы можете просто посмотреть, как распечатать System.getproperty ("java.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 Шаблоны проблем

7 голосов
/ 15 сентября 2015

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

Предположим, у нас есть пакет с именем 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

6 голосов
/ 10 августа 2015

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

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

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

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

5 голосов
/ 09 сентября 2015

Я получаю 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;
            }
        });
    }
}
4 голосов
/ 04 декабря 2018

Прочтите это, особенно если вы видите NoClassDefFoundErrors в ЕДИНЫХ ИСПЫТАНИЯХ ...


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

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


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

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

3 голосов
/ 07 ноября 2016

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

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

...