Чому я отримую NoClassDefFoundError на Java?


530

Я отримую, NoClassDefFoundErrorколи запускаю свою програму Java. Що зазвичай є причиною цього?


1
Я вважаю, що це також може статися, якщо ви не запускаєте програму java з правильним синтаксисом. Наприклад, ви повинні викликати свій клас із папки кореневої скриньки з повною назвою пакету (тобто, my.package.myClass). Я був би більш конкретний, якби міг, але я не дуже сильний хлопець. Я просто пам’ятаю, що псували це кілька разів.
відвертий хаддер

17
@BoltClock Нам потрібно канонічне запитання, щоб вказати на численні дублікати. Чому це не може бути?
Raedwald

21
Чи обмірковували ви змінити прийняту відповідь, щоб той, кому громада вважає більш цінним, був на самому верху?
Мартін Сміт

Відповіді:


264

Це викликано, коли є файл класу, від якого залежить ваш код, і він присутній під час компіляції, але не знайдений під час виконання. Шукайте відмінності у вашій складанні та час виконання.


1
У мене виникла помилка під час розміщення вихідного файлу під неправильним простором імен / пакетом. Я подумав, що можу просто помістити його куди завгодно, і компілятор був задоволений. Виявляється, я повинен був бути більш старанним для виконання, щоб також бути щасливим.
CenterOrbit

1
У мене була помилка одного разу, коли мій сервер втратив пам’ять під час завантаження файлу. Кожного разу, коли я спробував завантаження, я отримував би іншу помилку. Врешті-решт це сказало мені, що у мене не вистачає купи місця.
Джеймс М. Лежав

81
Ця відповідь не обов'язково відповідає дійсності і буде вводити в оману багатьох людей! Дивіться кращу відповідь від Джареда нижче.
Дейв Л.

4
@DaveL. Дякую! Відповідь Джареда з 400+ оновленнями - нижче! Одна відповідь з голосами -4 вгору (вниз?) Набагато вище. У логіці впорядкування відповідей SO є щось рибне.
Saurabh Patil

1
Для когось це давній кадр, але я зіткнувся з цією помилкою, тому що відповідний клас містив SimpleDateFormat, який був ініціалізований з недійсним символом (у мене був T посередині замість 'T').
Райан Д

817

Хоча можливо, що це пов'язано з невідповідністю класового шляху між часом компіляції та часом виконання, це не обов'язково відповідає дійсності.

У цьому випадку важливо тримати два-три різних винятки прямо в нашій голові:

  1. java.lang.ClassNotFoundException Цей виняток вказує на те, що клас не знайдено на шляху. Це вказує на те, що ми намагалися завантажити визначення класу, а клас не існував на класі.

  2. java.lang.NoClassDefFoundError Цей виняток вказує на те, що JVM розглядав внутрішню структуру даних визначення класу для визначення класу і не знаходив її. Це відрізняється від того, щоб сказати, що його не можна було завантажити з класового шляху. Зазвичай це вказує на те, що ми раніше намагалися завантажити клас з classpath, але це не вдалося чомусь - тепер ми намагаємося знову використовувати клас (і, таким чином, потрібно завантажити його, оскільки він не вдався минулого разу), але ми ' Ви навіть не збираєтеся його завантажувати, тому що раніше не вдалося завантажити його (і обгрунтовано підозрюємо, що знову не вдасться). Попередній збій може бути ClassNotFoundException або ExceptionInInitializerError (що вказує на збій у статичному блоці ініціалізації) або будь-яку кількість інших проблем. Справа в тому, що NoClassDefFoundError не обов'язково є проблемою класового шляху.


30
Дякуємо, що згадували про причину NoClassDefFoundError, це мені дуже допомогло! У моєму випадку ExceptionInInitializerError був кинутий раніше, саме так я дізнався про помилки в статичних блоках.
Томас

@Jred, Коли я отримую Error: Could not find or load main class, він буде класифікований під категорію помилок?
Вікрам

@Pops: Зробили мову більш докладною для вказівки об’єктів дієслів "спробувати" :)
Джаред

1
@Vikram "не вдалося знайти або завантажити основний клас" не є винятком Java, він викликається запуском (який перевіряє JAR і основний атрибут маніфесту).
eckes

2
ClassNotFoundException також кидається, коли клас має статичну ініціалізацію, яка видає помилку чи виняток. Вони, мабуть, повинні були вибрати іншу назву для цієї події.
coladict

124

Ось код для ілюстрації 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;
}

3
А причина полягає в тому, що після першої спроби jvm вже знає, що не буде працювати і кинути різний виняток вдруге?
ikamen

@ikamen Мабуть, він десь зберігав невдалу ініціалізацію класу SimpleCalculatorпісля ділення на нуль? Хтось має посилання на офіційну документацію щодо такої поведінки?
ᴠɪɴᴄᴇɴᴛ

4
@PhilipRego Не впевнений, що ви маєте на увазі під «чистим» NoClassDefFoundError. Перший new SimpleCalculator()виклик, ви отримуєте ExceptionInInitializerError, викликаний ArithmeticException. Другий раз, коли ви телефонуєте, new SimpleCalculator()ви отримуєте NoClassDefFoundError таким же чистим, як і будь-який інший. Справа в тому, що ви можете отримати NoClassDefFoundError з іншої причини, ніж SimpleCalculator.class, не перебуваючи на уроці під час виконання.
харперська

36

NoClassDefFoundError на Java

Визначення:

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

  2. Якщо клас був присутній під час компіляції, але він не доступний у java classpath під час виконання.

введіть тут опис зображення

Приклади:

  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, то видимість класу серед кількох Classloader також може спричинити java.lang.NoClassDefFoundError, див. Приклади та розділ сценаріїв для детального обговорення.
  3. Перевірте наявність файлу java.lang.ExceptionInInitializerError у вашому файлі журналу. NoClassDefFoundError через збій статичної ініціалізації є досить поширеним явищем.
  4. Оскільки NoClassDefFoundError є підкласом java.lang.LinkageError, він також може виникнути, якщо одна з таких залежностей, як рідна бібліотека, може бути недоступною.
  5. Будь-який сценарій запуску є переважаючою змінною середовища Classpath.
  6. Можливо, ви запускаєте свою програму за допомогою команди jar, а клас не визначався в атрибуті ClassPath файлу маніфесту.

Ресурси:

3 способи вирішити NoClassDefFoundError

java.lang.NoClassDefFoundError Шаблони проблем


1
Чудова відповідь. Я думаю, я спробував усе, що ти запропонував, і все ще маю цю проблему. Я можу виключити деякі з них через баночку, яка працює з весною, але, схоже, java.sql не подобається (в моєму випадку драйвер sap db для Хани).
JE Carter II

Його насправді називають System.getproperty ("java.class.path")
RIJIK

33

Я виявив, що іноді я отримую помилку NoClassDefFound, коли код компілюється з несумісною версією класу, знайденої під час виконання. Я пам'ятаю конкретний екземпляр з бібліотекою осі apache. На моєму маршруті виконання фактично було дві версії, і він підбирав застарілу та несумісну версію, а не правильну, викликаючи помилку NoClassDefFound. Це було в додатку для командного рядка, де я використовував команду, аналогічну цій.

set classpath=%classpath%;axis.jar

Мені вдалося підібрати відповідну версію за допомогою:

set classpath=axis.jar;%classpath%;

4
Мав те саме питання. Виявляється, я склав файл війни з Java7, але моя Tomcat установка використовувала Java6. Мені довелося оновити свої змінні середовища
duvo

4
Якщо це трапиться так, я скажу, що Java в заваді. +2, якщо це правда. Це ще не можливо підтвердити. Якщо виявиться істинним, знову зробить +1 (У коментарях)
supernova

7

Це найкраще рішення, яке я знайшов поки що.

Припустимо, у нас є пакет під назвою, org.mypackageщо містить класи:

  • HelloWorld (основний клас)
  • SupportClass
  • UtilClass

а файли, що визначають цей пакет, зберігаються фізично під каталогом D:\myprogram(в Windows) або /home/user/myprogram(в Linux).

Структура файлу буде виглядати приблизно так: введіть тут опис зображення

Коли ми викликаємо Java, ми вказуємо назву програми для запуску: org.mypackage.HelloWorld. Однак ми також повинні сказати Java, де шукати файли та каталоги, що визначають наш пакет. Отже, щоб запустити програму, ми повинні використовувати таку команду: введіть тут опис зображення


6

Я використовував Spring Framework з Maven і вирішив цю помилку в своєму проекті.

У класі сталася помилка виконання. Я читав властивість як ціле число, але коли він читав значення з файлу властивості, його значення було подвійним.

Весна не дала мені повного сліду стека того, на якій лінії не вдалося виконати. Це просто сказано NoClassDefFoundError. Але коли я виконав його як нативну програму Java (вийнявши її з MVC), це дало ExceptionInInitializerErrorпричину, яка була справжньою причиною, і саме так я виявив помилку.

Відповідь @ xli дала мені зрозуміти, що може бути неправильним у моєму коді.


1
Те саме трапилося зі мною при програмуванні сервлета ( NoClassDefFoundErrorнасправді викликано ExceptionInInitalizerError, що викликано DateTimeParseException). Це трохи оманливо, чи не так? Я знаю, що вони, мабуть, мали свої причини зробити так, але було б так приємно мати хоч невеликий натяк, що NoClassDefFoundErrorбув результатом іншого винятку, без необхідності виводити це. Просто кинути ExceptionInInitializerErrorзнову було б набагато зрозуміліше. Іноді зв’язок між ними може бути не таким очевидним.
Bartłomiej Zieliński

5

Я отримую 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;
            }
        });
    }
}

1
Посилання мертва. Спробуйте заархівовану версію: web.archive.org/web/20131216000019/https://blogs.oracle.com/…
avgvstvs

5

Один цікавий випадок, у якому ви можете побачити багато - NoClassDefFoundErrorsце коли:

  1. throwa 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.


4
Це досить проклята корисна порада в реальному житті. У мене просто була така ж ситуація з ініціалізаторами атрибутів класу. У вас є лише один раз шанс побачити актуальну проблему в журналі. Після завантаження (або спроби в будь-якому випадку) вам потрібно все перезапустити.
DailyFrankPeter

4

Наведена нижче методика мені допомагала багато разів:

System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

де TheNoDefFoundClass - клас, який може бути "втрачений" через перевагу старішої версії тієї ж бібліотеки, що використовується вашою програмою. Найчастіше це трапляється у випадках, коли клієнтське програмне забезпечення розміщується у домінуючому контейнері, озброєному власними завантажувачами та тоннами старовинних версій найпопулярніших ліб.


3

У випадку, якщо ви створили код (EMF тощо), може бути занадто багато статичних ініціалізаторів, які споживають увесь простір стека.

Див. Запитання про переповнення стека Як збільшити розмір стека Java? .


"ЕМП" ? Ви маєте на увазі " MEF " ?
Пітер Мортенсен

2
Ні. EMF як структура моделювання затемнення. У автомобільній галузі ми можемо зіткнутися з цією помилкою під час запуску створеного коду.
Айкут Клік

1

Я вирішив свою проблему, відключивши preDexLibraries для всіх модулів:

dexOptions {
        preDexLibraries false
        ...

1

NoClassDefFoundErrorтакож може статися, коли статичний ініціалізатор намагається завантажити пакет ресурсів, недоступний під час виконання, наприклад, файл властивостей, який впливає клас, намагається завантажити з META-INFкаталогу, але його немає. Якщо ви не ловите NoClassDefFoundError, іноді ви не зможете побачити повний слід стека; Щоб подолати це, ви можете тимчасово використати catchпункт для Throwable:

try {
    // Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
    Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}

Це неправильно. Відсутній ресурс не дасть вам цієї помилки. Ви отримаєте його лише у тому випадку, якщо клас відсутній.
Стівен C

@StephenC Можливо, варто наголосити на цій частині більше, але я написав for example a properties file that the affected class tries to load from the META-INF directory. Це насправді трапилося зі мною, і мені вдалося вирішити NoClassDefFoundError, додавши файл з відсутніми властивостями. Цю відповідь я додав саме тому, що ніхто не сподівався на цю помилку за вказаних обставин.
ᴠɪɴᴄᴇɴᴛ

1
Тоді ви пропустили щось дуже важливе у своєму поясненні, тому що єдиний спосіб, коли файл з відсутніми ресурсами міг спровокувати це виняток, це якщо ви намагаєтеся завантажити файл ресурсу в staticініціалізацію ... що спровокувало неперевірений виняток і викликало клас init провалитися. Будь-який неперевірений виняток, що поширюється зі статичної ініціалізації, зробив би це.
Stephen C

Якщо я помиляюся (тобто це не пов’язано з невдалою staticініціалізацією), мені було б цікаво побачити фактичний приклад (тобто MCVE), який демонструє поведінку.
Стівен С

1
@StephenC Ти абсолютно прав, але :( Я роздивився випадок, коли я зіткнувся з цією проблемою, і він дійсно включав статичний ініціалізатор, який намагався завантажити ресурсний пакет. Я буду доповнювати / виправляти свій опис причини. Дякую, що вказав на це вихід.
ᴠɪɴᴄᴇɴᴛ

1

Я отримав цю помилку, коли я додав залежність Maven іншого модуля до свого проекту, проблема остаточно була вирішена шляхом додавання -Xss2mдо параметра JVM моєї програми (за JDK5.0 за замовчуванням це один мегабайт). Вважається, що програмі не вистачає стека для завантаження класу.


0

Якщо хтось приходить сюди через java.lang.NoClassDefFoundError: org/apache/log4j/Loggerпомилку, в моєму випадку він був створений, тому що я використовував log4j 2 (але я не додав усі файли, які входять до нього), а в деякій бібліотеці залежностей використовувався log4j 1. Рішенням було додати Log4j 1.x міст: баночка, log4j-1.2-api-<version>.jarяка постачається з log4j 2. Детальніше про міграцію log4j 2 .


0

Дві різні копії одного і того ж проекту

У моєму випадку проблема полягала в нездатності Eclipse розмежувати дві різні копії одного і того ж проекту. У мене один заблокований на стволі (SVN-контроль версій), а інший працює в одній гілці за один раз. Я спробував одну зміну робочої копії як тестовий випадок JUnit, який включав вилучення приватного внутрішнього класу як публічного класу самостійно, і поки він працював, я відкриваю інший примірник проекту, щоб оглянути навколо якогось іншого частина коду, яка потребувала змін. У якийсь момент NoClassDefFoundErrorспливав скарги, що приватного внутрішнього класу там немає; подвійне клацання в сліді стека привело мене до вихідного файла в неправильній копії проекту.

Закриття копії проекту та запуск тестового випадку знову позбулося проблеми.


0

Ця помилка може бути викликана неперевіреними вимогами версії Java .

У моєму випадку мені вдалося усунути цю помилку під час створення розгорнутого проекту з відкритим кодом, перейшовши з Java 9 на Java 8 за допомогою SDKMAN! .

sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu

Потім робите чисту установку, як описано нижче.


Використовуючи Maven як інструмент збирання, іноді корисно - а також із задоволенням зробити чисту збірку "встановити", якщо тестування вимкнено .

mvn clean install -DskipTests

Тепер, коли все було побудовано та встановлено, ви можете продовжувати та виконувати тести.

mvn test

0

У мене виникли помилки NoClassDefFound, коли я не експортував клас на вкладці "Порядок та експорт" на шляху збірки Java мого проекту. Не забудьте поставити галочку на вкладці "Порядок та експорт" будь-яких залежностей, які ви додаєте до шляху збирання проекту. Див. Попередження Eclipse: XXXXXXXXXXX.jar не експортується чи публікується. Це може призвести ClassNotFoundExceptions .


0

Це може бути також тому, що ви копіюєте файл коду з IDE з певним іменем пакета і хочете спробувати запустити його за допомогою терміналу. Спершу вам доведеться видалити назву пакета з коду. Це трапляється зі мною.


0

У моєму випадку я отримував цю помилку через невідповідність версій JDK. Коли я спробував запустити додаток від Intelij, він не працював, але потім його запуск з командного рядка працював. Це відбувається тому, що Intelij намагався запустити його за допомогою програми Java 11 JDK, яка була встановлена, але в командному рядку вона працювала з Java 8 JDK. Після переключення цього параметра у меню Файл> Структура проекту> Налаштування проекту> Пакет SDK проекту він працював для мене.


0

Тут усі розповідають про деякі налаштування Java, проблеми JVM і т.д. Додаток Весна завантаження).


0

У мене виникла цікава проблема з NoClassDefFoundError в JavaEE, що працює з сервером Liberty. Я використовував адаптери ресурсів IMS, і мій сервер.xml вже мав адаптер ресурсів для imsudbJXA.rar. Коли я додав новий адаптер для imsudbXA.rar, я почав би отримувати цю помилку, наприклад, для об’єктів DLIException, IMSConnectionSpec або SQLInteractionSpec. Я не міг зрозуміти чому, але вирішив це, створивши новий сервер.xml для своєї роботи, використовуючи лише imsudbXA.rar. Я впевнений, що використання декількох адаптерів ресурсів у server.xml нормально, я просто не встиг вивчити це.


-1

Java не змогла знайти клас A під час виконання. Клас А був у проекті ArtClient Maven з іншого робочого простору. Тому я імпортував ArtClient до свого проекту Eclipse. Два моїх проекти використовували ArtClient як залежність. Я змінив посилання бібліотеки на посилання на проект для цих (Path Build -> Configure Build Path).

І проблема пішла.


-1

У мене була така ж проблема, і я був на складі багато годин.

Я знайшов рішення. У моєму випадку, був визначений статичний метод, обумовлений цим. JVM не може створити інший об'єкт цього класу.

Наприклад,

private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");

-6

Я отримав це повідомлення після видалення двох файлів із бібліотеки SRC, і коли я повернув їх, я постійно бачив це повідомлення про помилку.

Моє рішення було: Перезапустити Eclipse. З тих пір я більше не бачив цього повідомлення :-)


4
Це пояснюється найбільш голосованою відповіддю, коли ви вперше компілювали, файли були там, потім ви видаляли деякі файли, класи видаляли, тож під час виконання ви отримали ClassNotFound, потім ви переглядали їх назад, але все ж Eclipse не став зауважте, що згенеровані класи все ще відсутні, але після перезапуску Eclipse робочу область оновлено та класи знову доступні, але загалом це не рішення чи вирішення, рішення визначає, який клас / jar відсутній під час виконання класний шлях.
Хосе Мануель Гомес Альварес

-7

Переконайтеся, що це збігається у module:appта module:lib:

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

    defaultConfig {
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 11
        versionName "2.1"
    }

3
Наскільки ваше рішення якимось чином стосується цієї поширеної проблеми?
Тааві Ільвес

Конфігурація вибірки не врівноважена (три {sі два }). Ви можете це виправити?
Пітер Мортенсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.