Перейти к основному содержимому

ClassNotFoundException против NoClassDefFoundError

· 3 мин. чтения

1. Введение

И ClassNotFoundException , и NoClassDefFoundError возникают, когда JVM не может найти запрошенный класс в пути к классам. Хотя они выглядят знакомыми, между ними есть некоторые основные различия.

В этом уроке мы обсудим некоторые причины их появления и их решения.

2. Исключение ClassNotFoundException

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

В основном это происходит при попытке загрузить классы с помощью Class.forName() , ClassLoader.loadClass() или ClassLoader.findSystemClass() . Поэтому нам нужно быть особенно осторожными с java.lang.ClassNotFoundException при работе с отражением.

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

@Test(expected = ClassNotFoundException.class)
public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException()
throws ClassNotFoundException {
Class.forName("oracle.jdbc.driver.OracleDriver");
}

3. NoClassDefFoundError

NoClassDefFoundError — фатальная ошибка. Это происходит, когда JVM не может найти определение класса при попытке:

  • Создайте экземпляр класса, используя новое ключевое слово
  • Загрузите класс с вызовом метода

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

Давайте рассмотрим сценарий, который является одним из простых способов воспроизвести проблему. Инициализация ClassWithInitErrors вызывает исключение. Итак, когда мы пытаемся создать объект ClassWithInitErrors, он выдает ExceptionInInitializerError.

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

public class ClassWithInitErrors {
static int data = 1 / 0;
}
public class NoClassDefFoundErrorExample {
public ClassWithInitErrors getClassWithInitErrors() {
ClassWithInitErrors test;
try {
test = new ClassWithInitErrors();
} catch (Throwable t) {
System.out.println(t);
}
test = new ClassWithInitErrors();
return test;
}
}

Давайте напишем тестовый пример для этого сценария:

@Test(expected = NoClassDefFoundError.class)
public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() {

NoClassDefFoundErrorExample sample
= new NoClassDefFoundErrorExample();
sample.getClassWithInitErrors();
}

4. Разрешение

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

Давайте рассмотрим несколько подходов, которые мы можем рассмотреть при работе с любым из них:

  1. Нам нужно убедиться, что класс или jar, содержащие этот класс, доступны в пути к классам. Если нет, нам нужно добавить его
  2. Если он доступен в пути к классам приложения, то, скорее всего, путь к классам переопределяется. Чтобы исправить это, нам нужно найти точный путь к классам, используемый нашим приложением.
  3. Кроме того, если приложение использует несколько загрузчиков классов, классы, загруженные одним загрузчиком классов, могут быть недоступны для других загрузчиков классов. Чтобы правильно устранять неполадки, важно знать, как работают загрузчики классов в Java .

5. Резюме

Хотя оба эти исключения связаны с classpath и средой выполнения Java, которая не может найти класс во время выполнения, важно отметить их различия.

Среда выполнения Java создает исключение ClassNotFoundException при попытке загрузить класс только во время выполнения, а имя было предоставлено во время выполнения. В случае NoClassDefFoundError класс присутствовал во время компиляции, но среда выполнения Java не смогла найти его в пути к классам Java во время выполнения.

Как всегда, полный код всех примеров можно найти на GitHub .