Каковы причины и в чем различия между NoClassDefFoundError и ClassNotFoundException? - PullRequest
359 голосов
/ 22 сентября 2009

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

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

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

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

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

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

Ответы [ 15 ]

380 голосов
/ 22 сентября 2009

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

Для ClassNotFoundException:

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

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

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

Для NoClassDefFoundError:

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

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

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

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

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

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

80 голосов
/ 06 февраля 2010

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

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

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

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

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

private static SomeClass foo = new SomeClass();

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

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

33 голосов
/ 22 сентября 2009

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

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

29 голосов
/ 08 июля 2010

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, затем запустите, вызвав 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()) должен просто работать.

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

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

19 голосов
/ 24 сентября 2014

С 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 и запустите класс Test, он выдаст

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 пытается загрузить определение класса, и определение класса не найдено.

15 голосов
/ 08 июля 2010

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

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

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

11 голосов
/ 12 января 2015

Пример № 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.

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

9 голосов
/ 22 сентября 2009

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

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

С другой стороны, NoClassDefFoundError выбрасывается

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

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

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

8 голосов
/ 31 января 2016

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

enter image description here

7 голосов
/ 30 декабря 2015

По самим именам мы можем легко идентифицировать одно из Exception, а другое - из Error.

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

Ошибка: Это вовсе не исключения, это выходит за рамки возможностей программиста. Эти ошибки обычно генерируются 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.
...