Каковы причины и каковы различия между NoClassDefFoundError и ClassNotFoundException?

StackOverflow https://stackoverflow.com/questions/1457863

Вопрос

В чем разница между NoClassDefFoundError и ClassNotFoundException?

Что заставляет их выбрасываться?Как они могут быть решены?

Я часто сталкиваюсь с этими выбрасываемыми файлами при изменении существующего кода для включения новых файлов jar.Я использовал их как на стороне клиента, так и на стороне сервера для java-приложения, распространяемого через webstart.

Возможные причины, с которыми я столкнулся:

  1. пакеты, не включенные в build.xml для клиентской части кода
  2. путь к классу среды выполнения отсутствует для новых jar, которые мы используем
  3. версия конфликтует с предыдущей jar

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

Это было полезно?

Решение

Отличие от спецификаций Java API заключается в следующем.

Для ClassNotFoundException:

Генерируется, когда приложение пытается загрузить в класс через его строку назовите, используя:

  • В forName метод в классе Class.
  • В findSystemClass метод в классе ClassLoader.
  • В loadClass метод в классе ClassLoader.

но нет определения для класса с не удалось найти указанное имя.

Для NoClassDefFoundError:

Выбрасывается, если виртуальная машина Java или a ClassLoader экземпляр пытается загрузиться в определении класса (как часть обычного вызова метода или как часть создания нового экземпляра с использованием нового выражения ) и не удалось найти определение класса .

Искомое определение класса существовало, когда выполняемый в данный момент класс был скомпилирован, но определение больше не может быть найдено.

Итак, похоже, что NoClassDefFoundError возникает, когда исходный код был успешно скомпилирован, но во время выполнения требуемое class файлы не были найдены.Это может произойти при распространении или создании файлов JAR, где не все необходимые class файлы были включены.

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

Разница между этими двумя заключается в том, что один из них является Error а другой - это ExceptionNoClassDefFoundError является Error и это происходит из-за того, что у виртуальной машины Java возникли проблемы с поиском класса, который она ожидала найти.Программа, которая, как ожидалось, должна была работать во время компиляции, не может быть запущена из-за class файлы не найдены или не совпадают с теми, которые были созданы или встречались во время компиляции.Это довольно критическая ошибка, так как программа не может быть инициирована JVM.

С другой стороны, ClassNotFoundException является Exception, так что это в некоторой степени ожидаемо и является чем-то, что можно восстановить.Использование reflection is может быть подвержено ошибкам (поскольку есть некоторые ожидания, что все может пойти не так, как ожидалось.Проверка во время компиляции на наличие всех требуемых классов отсутствует, поэтому любые проблемы с поиском нужных классов появятся во время выполнения.

Другие советы

Исключение ClassNotFoundException выдается, когда указанный класс не найден загрузчиком классов.Обычно это означает, что класс отсутствует в CLASSPATH .Это также может означать, что рассматриваемый класс пытается быть загружен из другого класса, который был загружен в родительский classloader, и, следовательно, класс из дочернего classloader не виден.Иногда это имеет место при работе в более сложных средах, таких как сервер приложений (WebSphere печально известна такими проблемами с загрузчиком классов).

Люди часто склонны путать java.lang.NoClassDefFoundError с java.lang.ClassNotFoundException однако есть важное различие.Например, исключение (ошибка на самом деле, поскольку java.lang.NoClassDefFoundError является подклассом java.lang.Ошибка), как

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

это не означает, что класс ActiveMQConnectionFactory отсутствует в CLASSPATH .На самом деле все как раз наоборот.Это означает, что класс ActiveMQConnectionFactory был найден загрузчиком классов, однако при попытке загрузить класс он столкнулся с ошибкой при чтении определения класса.Обычно это происходит, когда рассматриваемый класс имеет статические блоки или члены, которые используют класс, который не найден загрузчиком классов.Итак, чтобы найти виновника, просмотрите исходный код рассматриваемого класса (в данном случае ActiveMQConnectionFactory) и найдите код, использующий статические блоки или статические члены.Если у вас нет доступа к исходному коду, то просто декомпилируйте его с помощью JAD.

Изучив код, допустим, вы нашли строку кода, подобную приведенной ниже, убедитесь, что класс SomeClass in указан в вашем CLASSPATH.

private static SomeClass foo = new SomeClass();

Совет :Чтобы узнать, к какому jar-файлу относится тот или иной класс, вы можете воспользоваться jarFinder веб-сайта .Это позволяет вам указать имя класса с помощью подстановочных знаков, и он выполняет поиск класса в своей базе данных jars.jarhoo позволяет вам делать то же самое, но его больше нельзя использовать бесплатно.

Если вы хотите определить, к какому jar-файлу принадлежит класс, по локальному пути, вы можете использовать такую утилиту, как jarscan ( http://www.inetfeedback.com/jarscan/ ).Вы просто указываете класс, который вы хотели бы найти, и путь к корневому каталогу, в котором вы хотели бы, чтобы он начал поиск класса в jars и zip-файлах.

NoClassDefFoundError в основном это ошибка привязки.Это происходит, когда вы пытаетесь создать экземпляр объекта (статически с помощью "new"), и он не найден, когда это было во время компиляции.

ClassNotFoundException является более общим и представляет собой исключение во время выполнения, когда вы пытаетесь использовать класс, который не существует.Например, у вас есть параметр в функции, который принимает интерфейс, и кто-то передает класс, который реализует этот интерфейс, но у вас нет доступа к классу.Он также охватывает случай динамической загрузки класса, такой как использование loadClass() или Class.forName().

Ошибка NoClassDefFoundError (NCDFE) возникает, когда ваш код запускает "new Y()" и не может найти класс Y.

Возможно, Y просто отсутствует в вашем загрузчике классов, как предполагают другие комментарии, но может быть, что класс Y не подписан или имеет недопустимую подпись, или что Y загружается другим загрузчиком классов, не видимым вашему коду, или даже что Y зависит от Z, который не может быть загружен по любой из вышеперечисленных причин.

Если это произойдет, то JVM запомнит результат загрузки X (NCDFE) и просто будет выдавать новый NCDFE каждый раз, когда вы запрашиваете Y, не сообщая вам, почему:

class a {
  static class b {}
  public static void main(String args[]) {
    System.out.println("First attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
    System.out.println("\nSecond attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
  }
}

сохраните это как a.java где-нибудь

Код просто пытается создать экземпляр нового класса "b" дважды, кроме этого, в нем нет никаких ошибок, и он ничего не делает.

Скомпилируйте код с помощью javac a.java, Затем запустите a , вызвав java -cp . a -- он должен просто распечатать две строки текста, и он должен работать нормально, без ошибок.

Затем удалите файл "a $b.class" (или заполните его мусором, или скопируйте a.class поверх него), чтобы имитировать отсутствующий или поврежденный класс.Вот что происходит:

First attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:5)
Caused by: java.lang.ClassNotFoundException: a$b
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    ... 1 more

Second attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:7)

Первый вызов приводит к исключению ClassNotFoundException (генерируемому загрузчиком классов, когда он не может найти класс), которое должно быть обернуто в непроверенный NoClassDefFoundError , поскольку рассматриваемый код (new b()) должно просто сработать.

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

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

От http://www.javaroots.com/2013/02/classnotfoundexception-vs.html:

ClassNotFoundException :возникает, когда загрузчик классов не смог найти требуемый класс в пути к классу.Итак, в принципе, вы должны проверить свой путь к классу и добавить класс в classpath .

NoClassDefFoundError :это сложнее отладить и найти причину.Это выдается, когда во время компиляции присутствуют требуемые классы, но во время выполнения классы изменены или удалены, или статическая инициализация класса вызвала исключения.Это означает, что загружаемый класс присутствует в classpath, но один из классов, которые требуются этому классу, либо удалены, либо не удалось загрузить компилятором.Таким образом, вы должны увидеть классы, которые зависят от этого класса.

Пример:

public class Test1
{
}


public class Test 
{
   public static void main(String[] args)
   {
        Test1 = new Test1();    
   }

}

Теперь, после компиляции обоих классов, если вы удалите Test1.class file и запустите тестовый класс, он выдаст

Exception in thread "main" java.lang.NoClassDefFoundError: Test
    at Test1.main(Test1.java:5)
Caused by: java.lang.ClassNotFoundException: Test
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 1 more

ClassNotFoundException:выдается, когда приложение пытается загрузиться в класс через его имя, но не удается найти определение для класса с указанным именем.

NoClassDefFoundError:выбрасывается, если виртуальная машина Java пытается загрузить определение класса, но определение класса не может быть найдено.

В чем причина получения каждой из них и любого мыслительного процесса о том, как бороться с такими ошибками?

Они тесно связаны.A ClassNotFoundException выдается, когда Java отправилась на поиск определенного класса по имени и не смогла успешно загрузить его.A NoClassDefFoundError выдается, когда Java искала класс, который был связан с каким-либо существующим кодом, но не смогла найти его по той или иной причине (например, неправильный путь к классу, неправильная версия Java, неправильная версия библиотеки) и является полностью фатальным, поскольку указывает на то, что что-то пошло не так.

Если у вас есть опыт работы на C, CNFE - это как неспособность dlopen()/dlsym() и NCDFE - это проблема с компоновщиком;во втором случае соответствующие файлы классов никогда не должны были быть фактически скомпилированы в той конфигурации, в которой вы пытаетесь их использовать.

Пример №1:

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}

Если com/example/Class1 не существует ни в одном из путей к классам, тогда Он выдает ClassNotFoundException.

Пример №2:

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}

Если com/example/Class2 существовал во время компиляции B, но не найден во время выполнения, затем он выдает NoClassDefFoundError.

Оба являются исключениями во время выполнения.

Исключение ClassNotFoundException выдается при попытке загрузить класс путем ссылки на него через строку.Например, параметр в Class.forName() является строкой, и это повышает вероятность передачи недопустимых двоичных имен в classloader.

Исключение ClassNotFoundException выдается при обнаружении потенциально недопустимого двоичного имени;например, если имя класса содержит символ '/', вы обязательно получите исключение ClassNotFoundException.Он также генерируется, когда класс, на который есть прямая ссылка, недоступен в classpath.

С другой стороны, NoClassDefFoundError / Ошибка в классе выбрасывается

  • когда фактическое физическое представление класса - файл .class недоступен,
  • или класс уже был загружен в другой classloader (обычно родительский classloader загрузил бы класс, и, следовательно, класс не может быть загружен снова),
  • или, если найдено несовместимое определение класса - имя в файле класса не соответствует запрошенному имени,
  • или (что наиболее важно), если зависимый класс не может быть найден и загружен.В этом случае класс, на который имеется прямая ссылка, возможно, был найден и загружен, но зависимый класс недоступен или не может быть загружен.Это сценарий, в котором класс, на который есть прямая ссылка, может быть загружен с помощью Class.forName или эквивалентных методов.Это указывает на сбой в связывании.

Короче говоря, ошибка NoClassDefFoundError обычно генерируется при операторах new() или вызовах метода, которые загружают ранее отсутствовавший класс (в отличие от загрузки классов на основе строк для ClassNotFoundException), когда загрузчик классов не может найти или загрузить определение (ы) класса.

В конце концов, реализация ClassLoader должна выдавать экземпляр ClassNotFoundException, когда он не может загрузить класс.Большинство пользовательских реализаций classloader выполняют это, поскольку они расширяют URLClassLoader.Обычно загрузчики классов явно не генерируют NoClassDefFoundError ни в одной из реализаций метода - это исключение обычно генерируется из JVM в компиляторе HotSpot, а не самим загрузчиком классов.

Разница между ClassNotFoundException И NoClassDefFoundError

enter image description here

С помощью самих названий мы можем легко идентифицировать одно из Exception а другой - из Error.

Исключение: Исключения возникают во время выполнения программы.Программист может обработать эти исключения с помощью блока try catch.У нас есть два типа исключений.Проверенное исключение, которое генерируется во время компиляции.Исключения во время выполнения, которые генерируются во время выполнения, эти исключения обычно возникают из-за плохого программирования.

Ошибка: Это вовсе не исключения, это выходит за рамки компетенции программиста.Эти ошибки обычно выдаются JVM.


enter image description here источник изображения

Разница:

Исключение ClassNotFoundException:

  • Загрузчику классов не удается проверить байтовый код класса, который мы упоминаем в Фаза соединения из подсистема загрузки классов мы получаем ClassNotFoundException.
  • ClassNotFoundException является ли проверяемое исключение производным непосредственно от java.lang.Exception класс, и вам нужно предоставить явную обработку для него
  • ClassNotFoundException появляется, когда есть явная загрузка определение класса осуществляется путем предоставления имени класса во время выполнения с помощью ClassLoader.loadClass(), Class.forName() и ClassLoader.findSystemClass().

NoClassDefFoundError / Ошибка в классе:

  • Загрузчику классов не удается разрешающий ссылки на класс в Фаза соединения из подсистема загрузки классов мы получаем NoClassDefFoundError.
  • NoClassDefFoundError является ли Ошибка производной от LinkageError класс, который используется для указания случаев ошибок, когда класс имеет зависимость от какого-либо другого класса и этот класс был несовместимо изменен после компиляции.
  • NoClassDefFoundError является результатом неявная загрузка класса из-за вызова метода из этого класса или любого доступа к переменной.

Сходства:

  • И то, и другое NoClassDefFoundError и ClassNotFoundException связаны с недоступностью класса во время выполнения.
  • И то, и другое ClassNotFoundException и NoClassDefFoundError связаны с Java classpath.

Учитывая действия загрузчика классов sussystem:

http://www.artima.com/insidejvm/ed2/images/fig7-1.gif

Это статья, которая очень помогла мне понять разницу: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

Если во время загрузки класса возникает ошибка, то экземпляр подкласса Ошибка LinkageError должен быть вызван в точке программы, которая (прямо или косвенно) использует загружаемый класс или интерфейс.

Если виртуальная машина Java когда-либо попытается загрузить класс C во время проверки (§ 5.4.1) или разрешения (§5.4.3) (но не инициализации (§5.5)), и загрузчик классов, который используется для инициализации загрузки C выдает экземпляр Исключение ClassNotFoundException, затем виртуальная Java Машина должна выдать экземпляр NoClassDefFoundError / Ошибка в классе чья причина является примером Исключение ClassNotFoundException.

Таким образом, a Исключение ClassNotFoundException является первопричиной NoClassDefFoundError / Ошибка в классе.
И a NoClassDefFoundError / Ошибка в классе является частным случаем ошибки загрузки типа, которая возникает при Связывание шаг.

Добавьте одну возможную причину на практике:

  • Исключение ClassNotFoundException:как сказал клетус, вы используете interface, в то время как унаследованный класс interface отсутствует в classpath .Например, Шаблон поставщика услуг (или Сервисный Локатор) попробуйте найти какой-нибудь несуществующий класс
  • NoClassDefFoundError / Ошибка в классе:данный класс найден, в то время как зависимость данного класса не найдена

На практике, Ошибка может быть выброшен молча, например, вы отправляете задачу таймера, и в задаче таймера она выдает Ошибка, в то время как в большинстве случаев ваша программа только улавливает Исключение.Затем в Таймер основной цикл завершается без какой-либо информации.Ошибка, аналогичная ошибке NoClassDefFoundError , является Ошибка ExceptionInInitializerError, когда ваш статический инициализатор или инициализатор статической переменной выдает исключение.

Исключение ClassNotFoundException является проверяемым исключением, которое возникает, когда мы указываем JVM загрузить класс по его строковому имени, используя методы Class.forName() или ClassLoader.findSystemClass() или ClassLoader.loadClass(), и указанный класс не найден в classpath.

В большинстве случаев это исключение возникает при попытке запустить приложение без обновления пути к классу необходимыми файлами JAR.Например, вы, возможно, видели это исключение при выполнении кода JDBC для подключения к вашей базе данных, т. е. MySQL, но в вашем classpath для этого нет JAR.

NoClassDefFoundError / Ошибка в классе ошибка возникает, когда JVM пытается загрузить определенный класс, который является частью выполнения вашего кода (как часть обычного вызова метода или как часть создания экземпляра с использованием ключевого слова new), и этот класс отсутствует в вашем classpath, но присутствовал во время компиляции, потому что для выполнения вашей программы вам нужно ее скомпилировать, и если вы пытаетесь использовать класс, которого нет, компилятор выдаст ошибку компиляции.

Ниже приведено краткое описание

enter image description here

Вы можете читать Все о ClassNotFoundException Против NoClassDefFoundError для получения более подробной информации.

Я снова и снова напоминаю себе следующее, когда мне нужно освежиться

Исключение ClassNotFoundException

Иерархия классов

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

Во время отладки

  1. Требуется jar, класс отсутствует в classpath.
  2. Убедитесь, что все необходимые jar-файлы находятся в classpath jvm.

NoClassDefFoundError / Ошибка в классе

Иерархия классов

NoClassDefFoundError extends LinkageError  extends Error extends Throwable

Во время отладки

  1. Проблема с динамической загрузкой класса, который был скомпилирован должным образом
  2. Проблема со статическими блоками, конструкторами, методами init() зависимого класса, и фактическая ошибка оборачивается несколькими слоями [особенно при использовании spring, hibernate фактическое исключение оборачивается, и вы получите NoClassDefError]
  3. Когда вы сталкиваетесь с "ClassNotFoundException" в статическом блоке зависимого класса
  4. Проблема с версиями класса.Это происходит, когда у вас есть две версии v1, v2 одного и того же класса в разных jar / пакетах, которые были успешно скомпилированы с использованием v1, а v2 загружается во время выполнения, которое не имеет соответствующих методов / переменных, и вы увидите это исключение.[Однажды я решил эту проблему, удалив дубликат связанного с log4j класса из нескольких jar, которые появились в classpath]

ClassNotFoundException и NoClassDefFoundError возникают, когда определенный класс не найден во время выполнения.Однако они возникают в разных сценариях.

ClassNotFoundException - это исключение, которое возникает при попытке загрузить класс во время выполнения с использованием методов Class.forName() или loadClass(), и упомянутые классы не найдены в classpath.

    public class MainClass
    {
        public static void main(String[] args)
        {
            try
            {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }



    java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError - это ошибка, возникающая, когда определенный класс присутствует во время компиляции, но отсутствовал во время выполнения.

    class A
    {
      // some code
    }
    public class B
    {
        public static void main(String[] args)
        {
            A a = new A();
        }
    }

Когда вы скомпилируете вышеуказанную программу, будут сгенерированы два файла .class .Один - это A.class, а другой - это B.class.Если вы удалите файл A.class и запустите файл B.class, Java Runtime System выдаст ошибку NoClassDefFoundError, как показано ниже:

    Exception in thread "main" java.lang.NoClassDefFoundError: A
    at MainClass.main(MainClass.java:10)
    Caused by: java.lang.ClassNotFoundException: A
    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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top