Я отримую, NoClassDefFoundError
коли запускаю свою програму Java. Що зазвичай є причиною цього?
Я отримую, NoClassDefFoundError
коли запускаю свою програму Java. Що зазвичай є причиною цього?
Відповіді:
Це викликано, коли є файл класу, від якого залежить ваш код, і він присутній під час компіляції, але не знайдений під час виконання. Шукайте відмінності у вашій складанні та час виконання.
Хоча можливо, що це пов'язано з невідповідністю класового шляху між часом компіляції та часом виконання, це не обов'язково відповідає дійсності.
У цьому випадку важливо тримати два-три різних винятки прямо в нашій голові:
java.lang.ClassNotFoundException
Цей виняток вказує на те, що клас не знайдено на шляху. Це вказує на те, що ми намагалися завантажити визначення класу, а клас не існував на класі.
java.lang.NoClassDefFoundError
Цей виняток вказує на те, що JVM розглядав внутрішню структуру даних визначення класу для визначення класу і не знаходив її. Це відрізняється від того, щоб сказати, що його не можна було завантажити з класового шляху. Зазвичай це вказує на те, що ми раніше намагалися завантажити клас з classpath, але це не вдалося чомусь - тепер ми намагаємося знову використовувати клас (і, таким чином, потрібно завантажити його, оскільки він не вдався минулого разу), але ми ' Ви навіть не збираєтеся його завантажувати, тому що раніше не вдалося завантажити його (і обгрунтовано підозрюємо, що знову не вдасться). Попередній збій може бути ClassNotFoundException або ExceptionInInitializerError (що вказує на збій у статичному блоці ініціалізації) або будь-яку кількість інших проблем. Справа в тому, що NoClassDefFoundError не обов'язково є проблемою класового шляху.
Error: Could not find or load main class
, він буде класифікований під категорію помилок?
Ось код для ілюстрації 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;
}
SimpleCalculator
після ділення на нуль? Хтось має посилання на офіційну документацію щодо такої поведінки?
new SimpleCalculator()
виклик, ви отримуєте ExceptionInInitializerError, викликаний ArithmeticException. Другий раз, коли ви телефонуєте, new SimpleCalculator()
ви отримуєте NoClassDefFoundError таким же чистим, як і будь-який інший. Справа в тому, що ви можете отримати NoClassDefFoundError з іншої причини, ніж SimpleCalculator.class, не перебуваючи на уроці під час виконання.
NoClassDefFoundError на Java
Визначення:
Віртуальна машина Java не в змозі знайти конкретний клас під час виконання, який був доступний під час компіляції.
Якщо клас був присутній під час компіляції, але він не доступний у java classpath під час виконання.
Приклади:
Простий приклад NoClassDefFoundError - клас належить до відсутнього файлу JAR або JAR не додано до classpath або іноді ім'я jar було змінено ким-то, як у моєму випадку один з моїх колег змінив tibco.jar на tibco_v3.jar і програма не вдається з java.lang.NoClassDefFoundError, і мені було цікаво, що не так.
Просто спробуйте запустити з явно -classpath варіантом з classpath, який, на вашу думку, спрацює, і якщо він працює, то це впевнений короткий знак того, що хтось переважає java classpath.
Можливі рішення:
Ресурси:
Я виявив, що іноді я отримую помилку NoClassDefFound, коли код компілюється з несумісною версією класу, знайденої під час виконання. Я пам'ятаю конкретний екземпляр з бібліотекою осі apache. На моєму маршруті виконання фактично було дві версії, і він підбирав застарілу та несумісну версію, а не правильну, викликаючи помилку NoClassDefFound. Це було в додатку для командного рядка, де я використовував команду, аналогічну цій.
set classpath=%classpath%;axis.jar
Мені вдалося підібрати відповідну версію за допомогою:
set classpath=axis.jar;%classpath%;
Це найкраще рішення, яке я знайшов поки що.
Припустимо, у нас є пакет під назвою, org.mypackage
що містить класи:
а файли, що визначають цей пакет, зберігаються фізично під каталогом D:\myprogram
(в Windows) або /home/user/myprogram
(в Linux).
Структура файлу буде виглядати приблизно так:
Коли ми викликаємо Java, ми вказуємо назву програми для запуску: org.mypackage.HelloWorld
. Однак ми також повинні сказати Java, де шукати файли та каталоги, що визначають наш пакет. Отже, щоб запустити програму, ми повинні використовувати таку команду:
Я використовував Spring Framework з Maven і вирішив цю помилку в своєму проекті.
У класі сталася помилка виконання. Я читав властивість як ціле число, але коли він читав значення з файлу властивості, його значення було подвійним.
Весна не дала мені повного сліду стека того, на якій лінії не вдалося виконати. Це просто сказано NoClassDefFoundError
. Але коли я виконав його як нативну програму Java (вийнявши її з MVC), це дало ExceptionInInitializerError
причину, яка була справжньою причиною, і саме так я виявив помилку.
Відповідь @ xli дала мені зрозуміти, що може бути неправильним у моєму коді.
NoClassDefFoundError
насправді викликано ExceptionInInitalizerError
, що викликано DateTimeParseException
). Це трохи оманливо, чи не так? Я знаю, що вони, мабуть, мали свої причини зробити так, але було б так приємно мати хоч невеликий натяк, що NoClassDefFoundError
був результатом іншого винятку, без необхідності виводити це. Просто кинути ExceptionInInitializerError
знову було б набагато зрозуміліше. Іноді зв’язок між ними може бути не таким очевидним.
Я отримую 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;
}
});
}
}
Один цікавий випадок, у якому ви можете побачити багато - NoClassDefFoundErrors
це коли:
throw
a RuntimeException
в static
блоці вашого класуExample
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
.
Наведена нижче методика мені допомагала багато разів:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
де TheNoDefFoundClass - клас, який може бути "втрачений" через перевагу старішої версії тієї ж бібліотеки, що використовується вашою програмою. Найчастіше це трапляється у випадках, коли клієнтське програмне забезпечення розміщується у домінуючому контейнері, озброєному власними завантажувачами та тоннами старовинних версій найпопулярніших ліб.
У випадку, якщо ви створили код (EMF тощо), може бути занадто багато статичних ініціалізаторів, які споживають увесь простір стека.
Див. Запитання про переповнення стека Як збільшити розмір стека Java? .
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);
}
for example a properties file that the affected class tries to load from the META-INF directory
. Це насправді трапилося зі мною, і мені вдалося вирішити NoClassDefFoundError
, додавши файл з відсутніми властивостями. Цю відповідь я додав саме тому, що ніхто не сподівався на цю помилку за вказаних обставин.
static
ініціалізацію ... що спровокувало неперевірений виняток і викликало клас init провалитися. Будь-який неперевірений виняток, що поширюється зі статичної ініціалізації, зробив би це.
static
ініціалізацією), мені було б цікаво побачити фактичний приклад (тобто MCVE), який демонструє поведінку.
Я отримав цю помилку, коли я додав залежність Maven іншого модуля до свого проекту, проблема остаточно була вирішена шляхом додавання -Xss2m
до параметра JVM моєї програми (за JDK5.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 .
У моєму випадку проблема полягала в нездатності Eclipse розмежувати дві різні копії одного і того ж проекту. У мене один заблокований на стволі (SVN-контроль версій), а інший працює в одній гілці за один раз. Я спробував одну зміну робочої копії як тестовий випадок JUnit, який включав вилучення приватного внутрішнього класу як публічного класу самостійно, і поки він працював, я відкриваю інший примірник проекту, щоб оглянути навколо якогось іншого частина коду, яка потребувала змін. У якийсь момент NoClassDefFoundError
спливав скарги, що приватного внутрішнього класу там немає; подвійне клацання в сліді стека привело мене до вихідного файла в неправильній копії проекту.
Закриття копії проекту та запуск тестового випадку знову позбулося проблеми.
Ця помилка може бути викликана неперевіреними вимогами версії 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
У мене виникли помилки NoClassDefFound, коли я не експортував клас на вкладці "Порядок та експорт" на шляху збірки Java мого проекту. Не забудьте поставити галочку на вкладці "Порядок та експорт" будь-яких залежностей, які ви додаєте до шляху збирання проекту. Див. Попередження Eclipse: XXXXXXXXXXX.jar не експортується чи публікується. Це може призвести ClassNotFoundExceptions .
У моєму випадку я отримував цю помилку через невідповідність версій JDK. Коли я спробував запустити додаток від Intelij, він не працював, але потім його запуск з командного рядка працював. Це відбувається тому, що Intelij намагався запустити його за допомогою програми Java 11 JDK, яка була встановлена, але в командному рядку вона працювала з Java 8 JDK. Після переключення цього параметра у меню Файл> Структура проекту> Налаштування проекту> Пакет SDK проекту він працював для мене.
Тут усі розповідають про деякі налаштування Java, проблеми JVM і т.д. Додаток Весна завантаження).
У мене виникла цікава проблема з NoClassDefFoundError в JavaEE, що працює з сервером Liberty. Я використовував адаптери ресурсів IMS, і мій сервер.xml вже мав адаптер ресурсів для imsudbJXA.rar. Коли я додав новий адаптер для imsudbXA.rar, я почав би отримувати цю помилку, наприклад, для об’єктів DLIException, IMSConnectionSpec або SQLInteractionSpec. Я не міг зрозуміти чому, але вирішив це, створивши новий сервер.xml для своєї роботи, використовуючи лише imsudbXA.rar. Я впевнений, що використання декількох адаптерів ресурсів у server.xml нормально, я просто не встиг вивчити це.
Java не змогла знайти клас A під час виконання. Клас А був у проекті ArtClient Maven з іншого робочого простору. Тому я імпортував ArtClient до свого проекту Eclipse. Два моїх проекти використовували ArtClient як залежність. Я змінив посилання бібліотеки на посилання на проект для цих (Path Build -> Configure Build Path).
І проблема пішла.
У мене була така ж проблема, і я був на складі багато годин.
Я знайшов рішення. У моєму випадку, був визначений статичний метод, обумовлений цим. JVM не може створити інший об'єкт цього класу.
Наприклад,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Я отримав це повідомлення після видалення двох файлів із бібліотеки SRC, і коли я повернув їх, я постійно бачив це повідомлення про помилку.
Моє рішення було: Перезапустити Eclipse. З тих пір я більше не бачив цього повідомлення :-)
Переконайтеся, що це збігається у module:app
та module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
і два }
). Ви можете це виправити?