Каковы причины и каковы различия между NoClassDefFoundError и ClassNotFoundException?
В чем разница между NoClassDefFoundError
а также ClassNotFoundException
?
Что заставляет их быть брошенными? Как они могут быть решены?
Я часто сталкиваюсь с этими throwables при изменении существующего кода, чтобы включить новые файлы JAR. Я ударил их как на стороне клиента, так и на стороне сервера для Java-приложения, распространяемого через веб-запуск.
Возможные причины, с которыми я столкнулся:
- пакеты не включены в
build.xml
для клиентской части кода - путь к классу во время выполнения отсутствует для новых банок, которые мы используем
- версия конфликтует с предыдущей флягой
Когда я сталкиваюсь с этим сегодня, я использую метод "след и ошибка", чтобы все заработало. Мне нужно больше ясности и понимания.
15 ответов
Отличие от спецификаций 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
, так что это несколько ожидаемо, и это то, что можно восстановить. Использование рефлексии может быть подвержено ошибкам (так как есть некоторые ожидания, что все может пойти не так, как ожидалось. Нет проверки во время компиляции, чтобы увидеть, что все необходимые классы существуют, поэтому любые проблемы с поиском нужных классов появятся во время выполнения,
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();
Совет: чтобы узнать, к какому jar принадлежит класс, вы можете использовать веб-сайт jarFinder. Это позволяет вам указать имя класса с помощью подстановочных знаков, и он ищет класс в своей базе данных jar. Jarhoo позволяет вам делать то же самое, но его больше нельзя использовать.
Если вы хотите определить, к какому jar-классу принадлежит класс, по локальному пути, вы можете использовать утилиту, например jarscan ( http://www.inetfeedback.com/jarscan/). Вы просто указываете класс, который хотите найти, и путь к корневому каталогу, где вы хотите начать поиск класса в jar-файлах и zip-файлах.
NoClassDefFoundError в основном является ошибкой связывания. Это происходит, когда вы пытаетесь создать экземпляр объекта (статически с помощью "new"), и не обнаруживается, когда это было во время компиляции.
ClassNotFoundException является более общим и является исключением времени выполнения, когда вы пытаетесь использовать класс, который не существует. Например, у вас есть параметр в функции, принимающий интерфейс, и кто-то передает класс, который реализует этот интерфейс, но у вас нет доступа к классу. Это также покрывает случай динамической загрузки класса, такой как использование loadClass() или Class.forName().
NoClassDefFoundError (NCDFE) происходит, когда ваш код выполняет "new Y ()" и не может найти класс Y.
Может просто случиться так, что Y отсутствует в загрузчике классов, как предлагают другие комментарии, но возможно, что класс Y не подписан или имеет недопустимую подпись, или что Y загружен другим загрузчиком классов, невидимым для вашего кода или даже то, что Y зависит от Z, который не может быть загружен по любой из вышеуказанных причин.
Если это произойдет, JVM запомнит результат загрузки X (NCDFE) и будет просто выдавать новый NCDFE каждый раз, когда вы запрашиваете Y, не сообщая вам, почему:
класс { статический класс b {} public static void main(String args[]) { System.out.println("Первая попытка нового b():"); попробуй {new b(); } catch(Throwable t) {t.printStackTrace();} System.out.println("\n Вторичная попытка нового b():"); попробуй {new b(); } catch(Throwable t) {t.printStackTrace();} } }
сохраните это как a.java где-нибудь
Код просто пытается дважды создать новый класс "b", кроме этого, в нем нет ошибок и он ничего не делает.
Скомпилируйте код с javac a.java
Затем запустите, применив java -cp . a
- он должен просто распечатать две строки текста, и он должен работать без ошибок.
Затем удалите файл "$ b.class" (или заполните его мусором, или скопируйте поверх него a.class), чтобы имитировать отсутствующий или поврежденный класс. Вот что происходит:
Первая попытка new b(): java.lang.NoClassDefFoundError: a$b в a.main(a.java:5) Причина: java.lang.ClassNotFoundException: a$b в java.net.URLClassLoader$1.run(URLClassLoader.java:200) на java.security.AccessController.doPrivileged(собственный метод) на java.net.URLClassLoader.findClass(URLClassLoader.java:188) на java.lang.ClassLoader.loadClass(ClassLoader.java:307) на солнце.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) в java.lang.ClassLoader.loadClass(ClassLoader.java:252) в java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) ... еще 1 секунда попытка нового b (): java.lang.NoClassDefFoundError: a $ b в a.main(a.java:7)
Первый вызов приводит к ClassNotFoundException (генерируется загрузчиком класса, когда он не может найти класс), который должен быть обернут в непроверенную NoClassDefFoundError, так как код, о котором идет речь (new b()
) должен просто работать.
Вторая попытка, конечно, тоже потерпит неудачу, но, как вы можете видеть, исключенное завертывание больше не существует, потому что ClassLoader, похоже, запоминает сбой загрузчиков классов. Вы видите только 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 и запустите класс 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 пытается загрузить определение класса, и определение класса не найдено.
Какова причина получения каждого из них и какой-либо мыслительный процесс о том, как бороться с такими ошибками?
Они тесно связаны. ClassNotFoundException
генерируется, когда Java отправляется на поиск определенного класса по имени и не может успешно его загрузить. 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
,
Оба являются исключениями времени выполнения.
С самими именами мы можем легко идентифицировать одно из
Exception
а другой изError
,
Исключение: исключения возникают во время выполнения программы. Программист может обработать это исключение, попробовав catch block. У нас есть два типа исключений. Проверено исключение, которое выдает во время компиляции. Исключения во время выполнения, которые генерируются во время выполнения, эти исключения обычно происходят из-за плохого программирования.
Ошибка: это вовсе не исключения, это выходит за рамки возможностей программиста. Эти ошибки обычно выдает JVM.
Разница:
ClassNotFoundException:
- Загрузчик классов не может проверить байт-код класса, который мы упоминаем в фазе Link подсистемы загрузки классов, которую мы получаем
ClassNotFoundException
, ClassNotFoundException
это проверенное исключение, полученное непосредственно изjava.lang.Exception
класс, и вы должны предоставить явную обработку для негоClassNotFoundException
возникает, когда происходит явная загрузка класса, путем предоставления имени класса во время выполнения с использованием ClassLoader.loadClass(), Class.forName() и ClassLoader.findSystemClass ().
NoClassDefFoundError:
- Загрузчик классов не может разрешить ссылки на класс в фазе Link подсистемы загрузки классов, которую мы получаем
NoClassDefFoundError
, NoClassDefFoundError
это ошибка, полученная изLinkageError
класс, который используется для указания случаев ошибок, когда класс зависит от какого-то другого класса, и этот класс несовместимо изменился после компиляции.NoClassDefFoundError
является результатом неявной загрузки класса из-за вызова метода из этого класса или любой переменной доступа.
сходства:
- И то и другое
NoClassDefFoundError
а такжеClassNotFoundException
связаны с недоступностью класса во время выполнения. - И то и другое
ClassNotFoundException
а такжеNoClassDefFoundError
связаны с Java classpath.
ClassNotFoundException выдается, когда есть попытка загрузить класс, ссылаясь на него через строку. Например, параметр to в Class.forName() является строкой, и это увеличивает вероятность того, что недопустимые двоичные имена будут переданы загрузчику классов.
ClassNotFoundException генерируется, когда встречается потенциально недопустимое двоичное имя; например, если имя класса имеет символ '/', вы обязаны получить исключение ClassNotFoundException. Он также генерируется, когда класс с прямой ссылкой недоступен в пути к классам.
С другой стороны, выбрасывается NoClassDefFoundError
- когда фактическое физическое представление класса - файл.class недоступен,
- или класс уже был загружен в другой загрузчик классов (обычно родительский загрузчик классов загружал бы класс и, следовательно, класс не может быть загружен снова),
- или если найдено несовместимое определение класса - имя в файле класса не совпадает с запрошенным именем,
- или (что наиболее важно), если зависимый класс не может быть найден и загружен. В этом случае класс, на который имеется прямая ссылка, мог быть найден и загружен, но зависимый класс недоступен или не может быть загружен. Это сценарий, в котором класс, на который есть прямая ссылка, может быть загружен с помощью Class.forName или эквивалентных методов. Это указывает на сбой в связи.
Короче говоря, NoClassDefFoundError обычно генерируется в операторах new() или вызовах методов, которые загружают ранее отсутствующий класс (в отличие от загрузки классов на основе строк для ClassNotFoundException), когда загрузчик классов не может найти или загрузить определение класса (с).
В конце концов, реализация ClassLoader создает экземпляр ClassNotFoundException, когда он не может загрузить класс. Большинство пользовательских реализаций загрузчика классов выполняют это, поскольку они расширяют URLClassLoader. Обычно загрузчики классов явно не генерируют NoClassDefFoundError ни в одной из реализаций метода - это исключение обычно генерируется из JVM в компиляторе HotSpot, а не самим загрузчиком классов.
Учитывая действия sussystem загрузчика класса:
Эта статья очень помогла мне понять разницу: 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.
Таким образом, ClassNotFoundException является основной причиной NoClassDefFoundError.
А NoClassDefFoundError - это особый случай ошибки загрузки типа, возникающей на этапе связывания.
ClassNotFoundException - это проверенное исключение, которое возникает, когда мы сообщаем JVM загружать класс по его строковому имени, используя методы Class.forName() или ClassLoader.findSystemClass() или ClassLoader.loadClass(), и упомянутый класс не найден в classpath.
В большинстве случаев это исключение возникает при попытке запустить приложение без обновления пути к классу необходимыми файлами JAR. Например, вы, возможно, видели это исключение при выполнении кода JDBC для подключения к вашей базе данных, т.е.MySQL, но ваш путь к классам не имеет JAR для него.
ОшибкаNoClassDefFoundError возникает, когда JVM пытается загрузить определенный класс, который является частью выполнения вашего кода (как часть обычного вызова метода или как часть создания экземпляра с использованием нового ключевого слова), и этот класс отсутствует в вашем пути к классам, но был присутствует во время компиляции, потому что для выполнения вашей программы вам нужно скомпилировать ее, и если вы пытаетесь использовать класс, которого нет, компилятор вызовет ошибку компиляции.
Ниже приводится краткое описание
Вы можете прочитать все о ClassNotFoundException против NoClassDefFoundError для более подробной информации.
Добавьте одну возможную причину на практике:
- ClassNotFoundException: как сказал Клетус, вы используете интерфейс, в то время как унаследованный класс интерфейса не находится в пути к классам. Например, шаблон сервис-провайдера (или сервис-локатор) пытается найти какой-то несуществующий класс
- NoClassDefFoundError: данный класс найден, а зависимость данного класса не найдена
На практике ошибка может быть выброшена без вывода сообщений, например, вы отправляете задачу таймера, а в задаче таймера она выдает ошибку, в то время как в большинстве случаев ваша программа только перехватывает исключение. Затем основной цикл таймера заканчивается без какой-либо информации. Ошибка, аналогичная NoClassDefFoundError, - это ExceptionInInitializerError, когда ваш статический инициализатор или инициализатор для статической переменной выдает исключение.
Я напоминаю себе следующее снова и снова, когда мне нужно обновить
ClassNotFoundException
Классовая иерархия
ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable
Во время отладки
- Необходимая банка, класс отсутствует в пути к классам.
- Убедитесь, что все необходимые фляги находятся в classpath jvm.
NoClassDefFoundError
Классовая иерархия
NoClassDefFoundError extends LinkageError extends Error extends Throwable
Во время отладки
- Проблема с динамической загрузкой класса, которая была правильно скомпилирована
- Проблема со статическими блоками, конструкторами, методами init() зависимого класса и фактической ошибкой оборачивается несколькими слоями [особенно когда вы используете spring, hibernate оборачивается фактическим исключением, и вы получите NoClassDefError]
- Когда вы сталкиваетесь с "ClassNotFoundException" под статическим блоком зависимого класса
- Проблема с версиями класса. Это происходит, когда у вас есть две версии v1, v2 одного и того же класса в разных jar/ пакетах, которые были успешно скомпилированы с использованием v1, а v2 загружается во время выполнения, в котором нет соответствующих методов /vars, и вы увидите это исключение. [Однажды я решил эту проблему, удалив дубликат связанного с log4j класса под несколькими банками, которые появились в classpath]
ClassNotFoundException и NoClassDefFoundError происходят, когда определенный класс не найден во время выполнения. Однако они происходят в разных сценариях.
ClassNotFoundException - это исключение, которое возникает, когда вы пытаетесь загрузить класс во время выполнения с помощью методов Class.forName() или loadClass(), и упомянутые классы не найдены в пути к классам.
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)