Ich erhalte eine, NoClassDefFoundError
wenn ich meine Java-Anwendung ausführe. Was ist typischerweise die Ursache dafür?
Ich erhalte eine, NoClassDefFoundError
wenn ich meine Java-Anwendung ausführe. Was ist typischerweise die Ursache dafür?
Antworten:
Dies wird verursacht, wenn es eine Klassendatei gibt, von der Ihr Code abhängt und die zur Kompilierungszeit vorhanden ist, aber zur Laufzeit nicht gefunden wird. Suchen Sie nach Unterschieden in Ihren Erstellungszeit- und Laufzeitklassenpfaden.
Es ist zwar möglich, dass dies auf eine Klassenübereinstimmung zwischen Kompilierungszeit und Laufzeit zurückzuführen ist, dies ist jedoch nicht unbedingt der Fall.
In diesem Fall ist es wichtig, zwei oder drei verschiedene Ausnahmen im Kopf zu behalten:
java.lang.ClassNotFoundException
Diese Ausnahme gibt an, dass die Klasse nicht im Klassenpfad gefunden wurde. Dies zeigt an, dass wir versucht haben, die Klassendefinition zu laden, und die Klasse im Klassenpfad nicht vorhanden war.
java.lang.NoClassDefFoundError
Diese Ausnahme gibt an, dass die JVM in ihrer internen Klassendefinitionsdatenstruktur nach der Definition einer Klasse gesucht und diese nicht gefunden hat. Dies unterscheidet sich von der Aussage, dass es nicht aus dem Klassenpfad geladen werden konnte. Normalerweise bedeutet dies, dass wir zuvor versucht haben, eine Klasse aus dem Klassenpfad zu laden, dies jedoch aus irgendeinem Grund fehlgeschlagen ist. Jetzt versuchen wir, die Klasse erneut zu verwenden (und müssen sie daher laden, da sie beim letzten Mal fehlgeschlagen ist). Ich werde nicht einmal versuchen, es zu laden, weil wir es früher nicht geladen haben (und vernünftigerweise vermuten, dass wir wieder scheitern würden). Der frühere Fehler kann eine ClassNotFoundException oder ein ExceptionInInitializerError sein (was auf einen Fehler im statischen Initialisierungsblock hinweist) oder eine beliebige Anzahl anderer Probleme. Der Punkt ist, dass ein NoClassDefFoundError nicht unbedingt ein Klassenpfadproblem ist.
Error: Could not find or load main class
wird es in welche Fehlerkategorie eingestuft?
Hier ist der Code zur Veranschaulichung java.lang.NoClassDefFoundError
. Weitere Informationen finden Sie in Jareds Antwort .
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
nach der Division durch Null gespeichert ? Hat jemand einen Verweis auf die offizielle Dokumentation für dieses Verhalten?
new SimpleCalculator()
Aufruf erhalten Sie einen ExceptionInInitializerError mit einem von ArithmeticException verursachten Fehler. Beim zweiten Aufruf erhalten new SimpleCalculator()
Sie einen NoClassDefFoundError, der so rein ist wie jeder andere. Der Punkt ist, dass Sie einen NoClassDefFoundError aus einem anderen Grund als SimpleCalculator.class erhalten können, der sich zur Laufzeit nicht im Klassenpfad befindet.
NoClassDefFoundError In Java
Definition:
Java Virtual Machine kann zur Laufzeit keine bestimmte Klasse finden, die zur Kompilierungszeit verfügbar war.
Wenn eine Klasse während der Kompilierungszeit vorhanden war, aber zur Laufzeit nicht im Java-Klassenpfad verfügbar war.
Beispiele:
Ein einfaches Beispiel für NoClassDefFoundError ist, dass die Klasse zu einer fehlenden JAR-Datei gehört oder dass JAR nicht zum Klassenpfad hinzugefügt wurde oder dass der Name von jar von jemandem geändert wurde, wie in meinem Fall einer meiner Kollegen tibco.jar in tibco_v3.jar geändert hat und das Programm ist Fehler mit java.lang.NoClassDefFoundError und ich haben uns gefragt, was los ist.
Versuchen Sie einfach, die explizite Option -classpath mit dem Klassenpfad auszuführen, von dem Sie glauben, dass er funktioniert. Wenn dies funktioniert, ist dies ein sicheres kurzes Zeichen dafür, dass jemand den Java-Klassenpfad überschreibt.
Mögliche Lösungen:
Ressourcen:
Ich habe festgestellt, dass manchmal ein NoClassDefFound-Fehler auftritt, wenn Code mit einer inkompatiblen Version der zur Laufzeit gefundenen Klasse kompiliert wird. Die spezifische Instanz, an die ich mich erinnere, ist die Apache-Achsenbibliothek. Es gab tatsächlich 2 Versionen in meinem Laufzeitklassenpfad und es wurde die veraltete und inkompatible Version und nicht die richtige Version gefunden, was einen NoClassDefFound-Fehler verursachte. Dies war in einer Befehlszeilen-App, in der ich einen ähnlichen Befehl verwendete.
set classpath=%classpath%;axis.jar
Ich konnte es dazu bringen, die richtige Version zu finden, indem ich Folgendes verwendete:
set classpath=axis.jar;%classpath%;
Dies ist die beste Lösung, die ich bisher gefunden habe.
Angenommen, wir haben ein Paket org.mypackage
mit den Klassen:
und die Dateien, die dieses Paket definieren, werden physisch im Verzeichnis D:\myprogram
(unter Windows) oder /home/user/myprogram
(unter Linux) gespeichert .
Die Dateistruktur sieht folgendermaßen aus:
Wenn wir Java aufrufen, geben wir den Namen der auszuführenden Anwendung an : org.mypackage.HelloWorld
. Wir müssen Java jedoch auch mitteilen, wo nach den Dateien und Verzeichnissen gesucht werden soll, die unser Paket definieren. Um das Programm zu starten, müssen wir den folgenden Befehl verwenden:
Ich habe Spring Framework mit Maven verwendet und diesen Fehler in meinem Projekt behoben.
In der Klasse ist ein Laufzeitfehler aufgetreten. Ich habe eine Eigenschaft als Ganzzahl gelesen, aber als sie den Wert aus der Eigenschaftendatei las, war ihr Wert doppelt so hoch.
Spring gab mir keine vollständige Stapelverfolgung darüber, auf welcher Zeile die Laufzeit fehlgeschlagen ist. Es sagte einfach NoClassDefFoundError
. Aber als ich es als native Java-Anwendung ausführte (aus MVC herausnahm), gab es an, ExceptionInInitializerError
welche die wahre Ursache war und wie ich den Fehler verfolgte.
Die Antwort von @ xli gab mir einen Einblick in das, was in meinem Code möglicherweise falsch ist.
NoClassDefFoundError
wurde tatsächlich durch verursacht ExceptionInInitalizerError
, was durch verursacht wurde DateTimeParseException
). Es ist ein bisschen irreführend, nicht wahr? Ich weiß, dass sie wahrscheinlich ihre Gründe hatten, es so zu machen, aber es wäre so schön, zumindest einen kleinen Hinweis zu haben, der das NoClassDefFoundError
Ergebnis einer anderen Ausnahme war, ohne dass man darauf schließen musste. Nur noch ExceptionInInitializerError
einmal zu werfen wäre viel klarer. Manchmal ist die Verbindung zwischen den beiden nicht so offensichtlich.
Ich erhalte NoClassFoundError, wenn vom Runtime Class Loader geladene Klassen nicht auf Klassen zugreifen können, die bereits vom Java Rootloader geladen wurden. Da sich die verschiedenen Klassenlader in verschiedenen Sicherheitsdomänen befinden (laut Java), erlaubt die JVM nicht, dass Klassen, die bereits vom Rootloader geladen wurden, im Adressraum des Laufzeitladers aufgelöst werden.
Führen Sie Ihr Programm mit 'java -javaagent: tracer.jar [IHRE Java-ARGS]' aus.
Es wird eine Ausgabe erzeugt, die die geladene Klasse und die Loader-Umgebung zeigt, die die Klasse geladen hat. Es ist sehr hilfreich zu verfolgen, warum eine Klasse nicht aufgelöst werden kann.
// 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;
}
});
}
}
Ein interessanter Fall, in dem Sie möglicherweise viel sehen, NoClassDefFoundErrors
ist, wenn Sie:
throw
a RuntimeException
im static
Block Ihrer KlasseExample
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
wird zusammen mit ExceptionInInitializerError
dem statischen Block geworfen RuntimeException
.
Dies ist besonders wichtig, wenn Sie NoClassDefFoundErrors
in Ihren EINHEITSTESTS sehen .
In gewisser Weise "teilen" Sie die static
Blockausführung zwischen Tests, aber die Initiale ExceptionInInitializerError
befindet sich nur in einem Testfall. Der erste, der die problematische Example
Klasse verwendet. Andere Testfälle, die die Example
Klasse verwenden, werden nur geworfen NoClassDefFoundErrors
.
Die folgende Technik hat mir oft geholfen:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
Dabei ist TheNoDefFoundClass die Klasse, die möglicherweise "verloren" geht, weil Sie eine ältere Version derselben Bibliothek bevorzugen, die von Ihrem Programm verwendet wird. Dies ist am häufigsten der Fall, wenn die Client-Software in einem dominanten Container bereitgestellt wird, der mit eigenen Klassenladern und Tonnen alter Versionen der beliebtesten Bibliotheken ausgestattet ist.
Wenn Sie Code generiert haben (EMF usw.), kann es zu viele statische Initialisierer geben, die den gesamten Stapelspeicher belegen.
Siehe Frage zum Stapelüberlauf. Wie kann die Java-Stapelgröße erhöht werden? .
NoClassDefFoundError
Dies kann auch auftreten, wenn ein statischer Initialisierer versucht, ein Ressourcenpaket zu laden, das zur Laufzeit nicht verfügbar ist, z. B. eine Eigenschaftendatei, die die betroffene Klasse aus dem META-INF
Verzeichnis zu laden versucht , aber nicht vorhanden ist. Wenn Sie nicht fangen NoClassDefFoundError
, können Sie manchmal nicht die vollständige Stapelverfolgung sehen. Um dies zu überwinden, können Sie vorübergehend eine catch
Klausel verwenden für 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
. Dies ist mir tatsächlich passiert und ich konnte das Problem beheben, NoClassDefFoundError
indem ich die fehlende Eigenschaftendatei hinzufügte. Ich habe diese Antwort genau hinzugefügt, weil man diesen Fehler unter den genannten Umständen nicht erwarten würde.
static
Initialisierung zu laden ... was eine ungeprüfte Ausnahme auslöste und die Klasse init auslöste Versagen. Jede ungeprüfte Ausnahme, die sich aus der statischen Initialisierung ausbreitet, würde dies tun.
static
liege (dh dies liegt nicht an einer fehlgeschlagenen Initialisierung), wäre ich an einem tatsächlichen Beispiel (z. B. einem MCVE) interessiert, das das Verhalten demonstriert.
Ich habe diesen Fehler erhalten, als ich meinem Projekt die Maven-Abhängigkeit eines anderen Moduls hinzufügte. Das Problem wurde schließlich durch Hinzufügen -Xss2m
zur JVM-Option meines Programms behoben (seit JDK5.0 ist es standardmäßig ein Megabyte). Es wird angenommen, dass das Programm nicht genügend Stapel hat, um die Klasse zu laden.
Wenn jemand aufgrund eines java.lang.NoClassDefFoundError: org/apache/log4j/Logger
Fehlers hierher kommt , wurde er in meinem Fall erstellt, weil ich log4j 2 verwendet habe (aber nicht alle mitgelieferten Dateien hinzugefügt habe), und einige Abhängigkeitsbibliotheken haben log4j 1 verwendet. Die Lösung bestand darin, Log4j hinzuzufügen 1.x Bridge: das log4j-1.2-api-<version>.jar
mit log4j gelieferte JAR 2. Weitere Informationen in der log4j 2- Migration .
In meinem Fall war das Problem die Unfähigkeit von Eclipse, zwischen zwei verschiedenen Kopien desselben Projekts zu unterscheiden. Ich habe einen auf Trunk gesperrt (SVN-Versionskontrolle) und den anderen, der jeweils in einem Zweig arbeitet. Ich habe eine Änderung in der Arbeitskopie als JUnit-Testfall ausprobiert, bei der eine private innere Klasse extrahiert wurde, um eine öffentliche Klasse für sich zu sein, und während sie funktionierte, öffne ich die andere Kopie des Projekts, um mich nach einer anderen umzusehen Teil des Codes, der geändert werden musste. Irgendwann NoClassDefFoundError
tauchten die auf und beschwerten sich, dass die private innere Klasse nicht da war; Durch Doppelklicken in den Stack-Trace gelangte ich zur Quelldatei in der falschen Projektkopie.
Durch Schließen der Trunk-Kopie des Projekts und erneutes Ausführen des Testfalls wurde das Problem behoben.
Dieser Fehler kann durch ungeprüfte Java-Versionsanforderungen verursacht werden.
In meinem Fall konnte ich diesen Fehler beim Erstellen eines hochkarätigen Open-Source-Projekts beheben, indem ich mit SDKMAN von Java 9 auf Java 8 wechselte! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Führen Sie dann eine Neuinstallation wie unten beschrieben durch.
Wenn Sie Maven als Build-Tool verwenden, ist es manchmal hilfreich - und in der Regel erfreulich -, einen sauberen Build mit deaktiviertem Test durchzuführen .
mvn clean install -DskipTests
Nachdem alles erstellt und installiert wurde, können Sie die Tests ausführen.
mvn test
Ich habe NoClassDefFound-Fehler erhalten, als ich keine Klasse auf der Registerkarte "Bestellen und Exportieren" im Java-Erstellungspfad meines Projekts exportiert habe. Stellen Sie sicher, dass auf der Registerkarte "Bestellen und Exportieren" ein Häkchen für alle Abhängigkeiten gesetzt ist, die Sie dem Erstellungspfad des Projekts hinzufügen. Siehe Eclipse-Warnung: XXXXXXXXXXX.jar wird nicht exportiert oder veröffentlicht. Es kann zur Laufzeit ClassNotFoundExceptions kommen .
In meinem Fall wurde dieser Fehler aufgrund einer Nichtübereinstimmung in den JDK-Versionen angezeigt. Als ich versuchte, die Anwendung von Intelij aus auszuführen, funktionierte sie nicht, aber dann funktionierte es über die Befehlszeile. Dies liegt daran, dass Intelij versucht hat, es mit dem Java 11 JDK auszuführen, das eingerichtet wurde, aber in der Befehlszeile mit dem Java 8 JDK ausgeführt wurde. Nachdem ich diese Einstellung unter Datei> Projekteinstellung> Projekteinstellungen> Projekt-SDK geändert hatte, funktionierte sie für mich.
Alle sprechen hier über Java-Konfigurationsmaterial, JVM-Probleme usw. In meinem Fall hatte der Fehler überhaupt nichts mit diesen Themen zu tun und hatte einen sehr trivialen und leicht zu lösenden Grund: Ich hatte eine falsche Anmerkung an meinem Endpunkt in meinem Controller ( Spring Boot-Anwendung).
Ich hatte ein interessantes Problem mit NoClassDefFoundError in JavaEE, das mit Liberty Server zusammenarbeitet. Ich habe IMS-Ressourcenadapter verwendet und meine server.xml hatte bereits einen Ressourcenadapter für imsudbJXA.rar. Wenn ich einen neuen Adapter für imsudbXA.rar hinzufügte, wurde dieser Fehler beispielsweise für Objekte für DLIException, IMSConnectionSpec oder SQLInteractionSpec angezeigt. Ich konnte nicht herausfinden warum, aber ich habe es behoben, indem ich eine neue server.xml für meine Arbeit nur mit imsudbXA.rar erstellt habe. Ich bin sicher, dass die Verwendung mehrerer Ressourcenadapter in server.xml in Ordnung ist. Ich hatte einfach keine Zeit, mich damit zu befassen.
Java konnte die Klasse A zur Laufzeit nicht finden. Klasse A befand sich im Maven-Projekt ArtClient aus einem anderen Arbeitsbereich. Also habe ich ArtClient in mein Eclipse-Projekt importiert. Zwei meiner Projekte verwendeten ArtClient als Abhängigkeit. Ich habe die Bibliotheksreferenz für diese in eine Projektreferenz geändert (Erstellungspfad -> Erstellungspfad konfigurieren).
Und das Problem ist weg.
Ich hatte das gleiche Problem und war viele Stunden auf Lager.
Ich habe die Lösung gefunden. In meinem Fall wurde aufgrund dessen die statische Methode definiert. Die JVM kann kein anderes Objekt dieser Klasse erstellen.
Zum Beispiel,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Ich habe diese Meldung erhalten, nachdem ich zwei Dateien aus der SRC-Bibliothek entfernt hatte, und als ich sie zurückbrachte, wurde diese Fehlermeldung immer wieder angezeigt.
Meine Lösung war: Starten Sie Eclipse neu. Seitdem habe ich diese Nachricht nicht mehr gesehen :-)
Stellen Sie sicher, dass dies in module:app
und übereinstimmt module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
und zwei }
). Kannst du das Reparieren?