Was ist der Unterschied zwischen NoClassDefFoundError
und ClassNotFoundException
?
Wodurch werden sie geworfen? Wie können sie gelöst werden?
Ich stoße oft auf diese Throwables, wenn ich vorhandenen Code so ändere, dass er neue JAR-Dateien enthält. Ich habe sie sowohl auf der Client-Seite als auch auf der Server-Seite für eine über Webstart verteilte Java App getroffen.
Mögliche Gründe, auf die ich gestoßen bin:
build.xml
für die Client-Seite des Codes enthalten sindWenn ich diesen heute begegne, gehe ich auf Spur und Irrtum ein, um die Dinge zum Laufen zu bringen. Ich brauche mehr Klarheit und Verständnis.
Der Unterschied zu den Java API-Spezifikationen ist wie folgt.
Für ClassNotFoundException
:
Wird ausgelöst, wenn eine Anwendung versucht, eine Klasse über ihren Zeichenfolgennamen zu laden.
- Die
forName
Methode in der KlasseClass
.- Die
findSystemClass
Methode in der KlasseClassLoader
.- Die
loadClass
Methode in der KlasseClassLoader
.es konnte jedoch keine Definition für die Klasse mit dem angegebenen Namen gefunden werden.
Für NoClassDefFoundError
:
Wird ausgelöst, wenn die Java Virtual Machine oder eine
ClassLoader
Instanz versucht, in die Definition einer Klasse zu laden (als Teil eines normalen Methodenaufrufs oder als Teil des Erstellens einer neuen Instanz mit der neue Ausdruck) und es konnte keine Definition der Klasse gefunden werden.Die gesuchte Klassendefinition war vorhanden, als die aktuell ausgeführte Klasse kompiliert wurde, aber die Definition wurde nicht mehr gefunden.
Es scheint also, dass NoClassDefFoundError
auftritt, wenn die Quelle erfolgreich kompiliert wurde, aber zur Laufzeit die erforderlichen class
-Dateien nicht gefunden wurden. Dies kann bei der Verteilung oder Produktion von JAR-Dateien vorkommen, bei denen nicht alle erforderlichen class
-Dateien enthalten waren.
Was ClassNotFoundException
anbelangt, so scheint dies möglicherweise darauf zurückzuführen zu sein, dass versucht wird, zur Laufzeit reflektierende Aufrufe an Klassen vorzunehmen, aber die Klassen, die das Programm aufzurufen versucht, sind nicht vorhanden.
Der Unterschied zwischen den beiden ist, dass einer ein Error
und der andere ein Exception
ist. Mit NoClassDefFoundError
ist ein Error
und es ergibt sich aus der Java) virtuellen Maschine, die Probleme beim Auffinden einer erwarteten Klasse hat. Ein Programm, bei dem erwartet wurde, dass es funktioniert Die Kompilierungszeit kann nicht ausgeführt werden, da class
-Dateien nicht gefunden wurden oder nicht mit den Dateien übereinstimmen, die zur Kompilierungszeit erstellt wurden oder aufgetreten sind. Dies ist ein ziemlich kritischer Fehler, da das Programm nicht vom gestartet werden kann JVM.
Auf der anderen Seite ist ClassNotFoundException
ein Exception
, es wird also etwas erwartet, und es ist etwas, das wiederhergestellt werden kann. Die Verwendung von Reflection kann fehleranfällig sein (da zu erwarten ist, dass die Dinge nicht wie erwartet verlaufen). Es wird keine Überprüfung zur Kompilierungszeit durchgeführt, um festzustellen, ob alle erforderlichen Klassen vorhanden sind. Daher treten Probleme beim Auffinden der gewünschten Klassen zur Laufzeit auf .
Eine ClassNotFoundException wird ausgelöst, wenn die gemeldete Klasse vom ClassLoader nicht gefunden wird. Dies bedeutet normalerweise, dass die Klasse in CLASSPATH fehlt. Dies kann auch bedeuten, dass die betreffende Klasse versucht, von einer anderen Klasse geladen zu werden, die in einem übergeordneten Klassenladeprogramm geladen wurde. Daher ist die Klasse aus dem untergeordneten Klassenladeprogramm nicht sichtbar. Dies ist manchmal der Fall, wenn Sie in komplexeren Umgebungen wie einem App Server arbeiten (WebSphere ist für solche Classloader-Probleme berüchtigt).
Leute neigen oft dazu, Java.lang.NoClassDefFoundError
Mit Java.lang.ClassNotFoundException
Zu verwechseln, aber es gibt einen wichtigen Unterschied. Zum Beispiel eine Ausnahme (ein Fehler wirklich, da Java.lang.NoClassDefFoundError
Eine Unterklasse von Java.lang.Error ist) wie
Java.lang.NoClassDefFoundError:
org/Apache/activemq/ActiveMQConnectionFactory
bedeutet nicht, dass die ActiveMQConnectionFactory-Klasse nicht in CLASSPATH enthalten ist. Tatsächlich ist es ganz im Gegenteil. Dies bedeutet, dass die Klasse ActiveMQConnectionFactory vom ClassLoader gefunden wurde. Beim Versuch, die Klasse zu laden, ist jedoch ein Fehler beim Lesen der Klassendefinition aufgetreten. Dies ist normalerweise der Fall, wenn die betreffende Klasse statische Blöcke oder Member enthält, die eine Klasse verwenden, die vom ClassLoader nicht gefunden wird. Um den Täter zu finden, zeigen Sie die Quelle der betreffenden Klasse an (in diesem Fall ActiveMQConnectionFactory) und suchen Sie mit statischen Blöcken oder statischen Elementen nach Code. Wenn Sie keinen Zugriff auf die Quelle haben, dekompilieren Sie sie einfach mit JAD.
Wenn Sie den Code untersuchen, sagen Sie, Sie finden eine Codezeile wie unten, und stellen Sie sicher, dass die Klasse SomeClass in Ihrem CLASSPATH enthalten ist.
private static SomeClass foo = new SomeClass();
Tipp: Um herauszufinden, zu welchem Jar eine Klasse gehört, können Sie die Website jarFinder verwenden. Auf diese Weise können Sie einen Klassennamen mithilfe von Platzhaltern angeben und in der Datenbank der JAR-Dateien nach der Klasse suchen. Mit jarhoo können Sie dasselbe tun, es ist jedoch nicht mehr kostenlos.
Wenn Sie in einem lokalen Pfad herausfinden möchten, zu welchem Jar eine Klasse gehört, können Sie ein Hilfsprogramm wie jarscan ( http://www.inetfeedback.com/jarscan/ ) verwenden. Geben Sie einfach die Klasse an, nach der Sie suchen möchten, und den Stammverzeichnispfad, in dem die Suche nach der Klasse in JARS und ZIP-Dateien beginnen soll.
NoClassDefFoundError
ist grundsätzlich ein Verknüpfungsfehler. Es tritt auf, wenn Sie versuchen, ein Objekt zu instanziieren (statisch mit "new"), und es wird nicht gefunden, als es beim Kompilieren war.
ClassNotFoundException
ist allgemeiner und stellt eine Laufzeitausnahme dar, wenn Sie versuchen, eine Klasse zu verwenden, die nicht vorhanden ist. Sie haben beispielsweise einen Parameter in einer Funktion, der eine Schnittstelle akzeptiert, und jemand übergibt eine Klasse, die diese Schnittstelle implementiert, aber Sie haben keinen Zugriff auf die Klasse. Es wird auch der Fall des Ladens dynamischer Klassen behandelt, z. B. die Verwendung von loadClass()
oder Class.forName()
.
NoClassDefFoundError (NCDFE) tritt auf, wenn in Ihrem Code "new Y ()" ausgeführt wird und die Y-Klasse nicht gefunden wird.
Es kann einfach sein, dass Y in Ihrem Klassenladeprogramm fehlt, wie in den anderen Kommentaren vorgeschlagen, aber es kann sein, dass die Y-Klasse nicht signiert ist oder eine ungültige Signatur hat, oder dass Y von einem anderen Klassenladeprogramm geladen wird, das für Ihren Code nicht sichtbar ist , oder sogar, dass Y von Z abhängt, das aus den oben genannten Gründen nicht geladen werden konnte.
In diesem Fall merkt sich die JVM das Ergebnis des Ladens von X (NCDFE) und wirft jedes Mal, wenn Sie nach Y fragen, einfach ein neues NCDFE, ohne anzugeben, warum:
class a { static class b {} public static void main (String args []) { System.out.println ("Erster Versuch new b (): "); try {new b (); } catch (Throwable t) {t.printStackTrace ();} System.out.println ("\ nZweiter Versuch new b ():"); try {new b (); } catch (Throwable t) {t.printStackTrace ();} } }
speichere das irgendwo als .Java
Der Code versucht lediglich zweimal, eine neue "b" -Klasse zu instanziieren. Ansonsten hat er keine Bugs und macht nichts.
Kompilieren Sie den Code mit javac a.Java
Und führen Sie dann ein aus, indem Sie Java -cp . a
Aufrufen. Es sollte nur zwei Textzeilen ausgeben und fehlerfrei funktionieren.
Löschen Sie dann die Datei "a $ b.class" (oder füllen Sie sie mit Müll oder kopieren Sie eine Klasse darüber), um die fehlende oder beschädigte Klasse zu simulieren. Folgendes passiert:
Erster Versuch new b (): Java.lang.NoClassDefFoundError: a $ b Um a.main (a.Java:5) Auslöser: Java.lang.ClassNotFoundException: a $ b Bei Java.net.URLClassLoader $ 1.run (URLClassLoader.Java:200) Bei Java.security.AccessController.doPrivileged (native Methode) bei Java.net.URLClassLoader.findClass (URLClassLoader.Java:188) bei Java.lang.ClassLoader.loadClass (ClassLoader.Java:307) bei Sun.misc.Launcher $ AppClassLoader .loadClass (Launcher.Java:301) bei Java.lang.ClassLoader.loadClass (ClassLoader.Java:252) bei Java.lang.ClassLoader.loadClassInternal (ClassLoader.Java:320) ... 1 weiterer Zweiter Versuch new b (): Java.lang.NoClassDefFoundError: a $ b At a.main ( a.Java:7)
Der erste Aufruf führt zu einer ClassNotFoundException (die vom Klassenladeprogramm ausgelöst wird, wenn die Klasse nicht gefunden wird), die in einen ungeprüften NoClassDefFoundError eingeschlossen werden muss, da der fragliche Code (new b()
) nur funktionieren sollte.
Der zweite Versuch wird natürlich auch fehlschlagen, aber wie Sie sehen, ist die umschlossene Ausnahme nicht mehr vorhanden, da sich der ClassLoader anscheinend an ausgefallene Klassenladeprogramme erinnert. Sie sehen nur die NCDFE mit absolut keiner Ahnung, was wirklich passiert ist.
Wenn Sie also jemals ein NCDFE ohne Grundursache sehen, müssen Sie prüfen, ob Sie bis zum allerersten Laden der Klasse zurückverfolgen können, um die Fehlerursache zu finden.
Von http://www.javaroots.com/2013/02/classnotfoundexception-vs.html :
ClassNotFoundException
: Tritt auf, wenn der Klassenlader die erforderliche Klasse im Klassenpfad nicht finden konnte. Grundsätzlich sollten Sie also Ihren Klassenpfad überprüfen und die Klasse in den Klassenpfad einfügen.
NoClassDefFoundError
: Dies ist schwieriger zu debuggen und den Grund zu finden. Dies wird ausgelöst, wenn zur Kompilierungszeit die erforderlichen Klassen vorhanden sind, aber zur Laufzeit die Klassen geändert oder entfernt werden oder die statische Initialisierung der Klasse Ausnahmen auslöst. Dies bedeutet, dass die Klasse, die geladen wird, im Klassenpfad vorhanden ist, aber eine der Klassen, die von dieser Klasse benötigt werden, entweder entfernt wurde oder vom Compiler nicht geladen werden konnte. Sie sollten also die Klassen sehen, die von dieser Klasse abhängig sind.
Beispiel :
public class Test1
{
}
public class Test
{
public static void main(String[] args)
{
Test1 = new Test1();
}
}
Wenn Sie nach dem Kompilieren der beiden Klassen die Datei Test1.class löschen und Test class ausführen, wird sie ausgelöst
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
: Wird ausgelöst, wenn eine Anwendung versucht, eine Klasse über ihren Namen zu laden, aber keine Definition für die Klasse mit dem angegebenen Namen gefunden werden konnte.
NoClassDefFoundError
: wird ausgelöst, wenn die virtuelle Maschine Java) versucht, in die Definition einer Klasse zu laden, und keine Definition der Klasse gefunden werden konnte.
Was ist der Grund, warum jeder von ihnen und jeder Denkprozess dazu angehalten wird, mit solchen Fehlern umzugehen?
Sie sind eng miteinander verwandt. Ein ClassNotFoundException
wird ausgelöst, wenn Java nach einer bestimmten Klasse mit Namen gesucht hat und diese nicht erfolgreich laden konnte. Ein NoClassDefFoundError
wird ausgelöst, wenn Java hat nach einer Klasse gesucht, die in einen vorhandenen Code eingebunden war, diesen aber aus dem einen oder anderen Grund nicht gefunden hat (z. B. falscher Klassenpfad, falsche Java-Version, falsche Version einer Bibliothek) und ist äußerst schwerwiegend wie es anzeigt, dass etwas schief gelaufen ist.
Wenn Sie einen C-Hintergrund haben, ist ein CNFE wie ein Fehler bei dlopen()
/dlsym()
, und ein NCDFE ist ein Problem mit dem Linker. Im zweiten Fall sollten die betreffenden Klassendateien niemals in der Konfiguration kompiliert worden sein, in der Sie sie verwenden möchten.
Beispiel 1:
class A{
void met(){
Class.forName("com.example.Class1");
}
}
Wenn com/example/Class1
existiert in keinem der Klassenpfade, dann wirft es ClassNotFoundException
.
Beispiel # 2:
Class B{
void met(){
com.example.Class2 c = new com.example.Class2();
}
}
Wenn com/example/Class2
existierte beim Kompilieren von B, wurde aber während der Ausführung nicht gefunden. Dann wirft es NoClassDefFoundError
.
Beides sind Laufzeitausnahmen.
ClassNotFoundException wird ausgelöst, wenn versucht wird, die Klasse zu laden, indem auf sie über einen String verwiesen wird. Beispielsweise ist der Parameter in Class.forName () ein String, und dies erhöht die Wahrscheinlichkeit, dass ungültige Binärnamen an das Klassenladeprogramm übergeben werden.
Die ClassNotFoundException wird ausgelöst, wenn ein möglicherweise ungültiger Binärname festgestellt wird. Wenn der Klassenname beispielsweise das Zeichen '/' enthält, müssen Sie eine ClassNotFoundException abrufen. Es wird auch ausgelöst, wenn die direkt referenzierte Klasse im Klassenpfad nicht verfügbar ist.
Andererseits wird NoClassDefFoundError geworfen
Kurz gesagt, ein NoClassDefFoundError wird normalerweise bei new () - Anweisungen oder Methodenaufrufen ausgelöst, die eine zuvor fehlende Klasse laden (im Gegensatz zum stringbasierten Laden von Klassen für ClassNotFoundException), wenn der Klassenladeprogramm die Klassendefinition nicht finden oder laden kann ( s).
Schließlich muss die Implementierung von ClassLoader eine Instanz von ClassNotFoundException auslösen, wenn eine Klasse nicht geladen werden kann. Die meisten benutzerdefinierten Classloader-Implementierungen führen dies aus, da sie den URLClassLoader erweitern. Normalerweise lösen Klassenladeprogramme keinen NoClassDefFoundError explizit für eine der Methodenimplementierungen aus. Diese Ausnahme wird normalerweise von der JVM im HotSpot-Compiler und nicht vom Klassenladeprogramm selbst ausgelöst.
An den Namen selbst können wir leicht einen von
Exception
und einen vonError
identifizieren.
Ausnahme: Während der Programmausführung treten Ausnahmen auf. Ein Programmierer kann mit dieser Ausnahme umgehen, indem er den catch-Block versucht. Wir haben zwei Arten von Ausnahmen. Überprüfte Ausnahme, die beim Kompilieren ausgelöst wird. Laufzeit-Ausnahmen, die zur Laufzeit ausgelöst werden. Diese Ausnahmen treten normalerweise aufgrund einer schlechten Programmierung auf.
Fehler: Dies sind keine Ausnahmen, es liegt außerhalb des Rahmens des Programmierers. Diese Fehler werden normalerweise von JVM ausgelöst.
Unterschied:
ClassNotFoundException:
ClassNotFoundException
.ClassNotFoundException
ist eine aktivierte Ausnahme, die direkt von der Klasse Java.lang.Exception
abgeleitet wurde, und Sie müssen eine explizite Behandlung dafür bereitstellenClassNotFoundException
wird aufgerufen, wenn eine explizite Belastung der Klasse vorliegt, indem der Name der Klasse zur Laufzeit mit ClassLoader.loadClass () angegeben wird. Class.forName () und ClassLoader.findSystemClass ().NoClassDefFoundError:
NoClassDefFoundError
.NoClassDefFoundError
ist ein von der Klasse LinkageError
abgeleiteter Fehler, der verwendet wird, um Fehlerfälle anzuzeigen, in denen eine Klasse von einer anderen Klasse abhängig ist und diese Klasse sich nach der Kompilierung inkompatibel geändert hat.NoClassDefFoundError
ist das Ergebnis des impliziten Ladens einer Klasse aufgrund eines Methodenaufrufs dieser Klasse oder eines beliebigen Variablenzugriffs.Ähnlichkeiten:
NoClassDefFoundError
als auch ClassNotFoundException
stehen im Zusammenhang mit der Nichtverfügbarkeit einer Klasse zur Laufzeit.ClassNotFoundException
als auch NoClassDefFoundError
beziehen sich auf Java classpath.In Anbetracht der Aktionen des Klassenladeprogramms:
Dies ist ein Artikel, der mir sehr geholfen hat, den Unterschied zu verstehen: http://docs.Oracle.com/javase/specs/jvms/se7/html/jvms-5.html
Wenn beim Laden der Klasse ein Fehler auftritt, muss eine Instanz einer Unterklasse von LinkageError an einer Stelle im Programm ausgelöst werden, die (direkt oder indirekt) verwendet wird Die Klasse oder Schnittstelle, die geladen wird.
Wenn die Java Virtual Machine jemals versucht, eine Klasse C während der Überprüfung (§5.4.1) oder Auflösung (§5.4.3) (aber nicht Initialisierung (§5.5)) und der Klasse zu laden Loader, mit dem das Laden von C eingeleitet wird, löst eine Instanz von ClassNotFoundException aus. Anschließend muss die Java= Virtual Machine eine Instanz von NoClassDefFoundError , deren Ursache die Instanz von ClassNotFoundException ist.
Also ist eine ClassNotFoundException eine Grundursache für NoClassDefFoundError.
Und ein NoClassDefFoundError ist ein Sonderfall eines Typladefehlers, der im Verknüpfungsschritt auftritt.
Fügen Sie einen möglichen Grund in der Praxis hinzu:
In der Praxis kann Fehler geworfen werden still, z. B. Sie übermitteln eine Timer-Aufgabe, und in der Timer-Aufgabe wirft sie Fehler, während in den meisten Fällen Ihr Programm nur abfängt Ausnahme. Dann wird die Timer Hauptschleife ohne Information beendet. Ein ähnlicher Fehler wie bei NoClassDefFoundError ist ExceptionInInitializerError , wenn Ihr statischer Initialisierer oder der Initialisierer für eine statische Variable eine Ausnahme auslöst.
ClassNotFoundException ist eine aktivierte Ausnahme, die auftritt, wenn wir JVM anweisen, eine Klasse anhand ihres Zeichenfolgennamens mit Class.forName () oder ClassLoader.findSystemClass () oder zu laden Die Methoden ClassLoader.loadClass () und die erwähnte Klasse wurden im Klassenpfad nicht gefunden.
Meistens tritt diese Ausnahme auf, wenn Sie versuchen, eine Anwendung auszuführen, ohne den Klassenpfad mit den erforderlichen JAR-Dateien zu aktualisieren. Beispielsweise ist diese Ausnahme möglicherweise aufgetreten, wenn Sie den JDBC-Code zum Herstellen einer Verbindung mit Ihrer Datenbank, d. H. MySQL, ausführen, Ihr Klassenpfad enthält jedoch keine JAR-Datei dafür.
NoClassDefFoundError Fehler tritt auf, wenn JVM versucht, eine bestimmte Klasse zu laden, die Teil Ihrer Codeausführung ist (als Teil eines normalen Methodenaufrufs oder als Teil der Erstellung) Eine Instanz, die das neue Schlüsselwort verwendet, und diese Klasse sind nicht in Ihrem Klassenpfad vorhanden, waren jedoch zur Kompilierungszeit vorhanden, da Sie sie kompilieren müssen, um Ihr Programm auszuführen. Wenn Sie versuchen, eine Klasse zu verwenden, die nicht vorhanden ist, wird der Compiler die Kompilierung auslösen Error.
Unten ist die kurze Beschreibung
Sie können lesen Alles über ClassNotFoundException Vs NoClassDefFoundError für weitere Details.
Ich erinnere mich immer wieder an Folgendes, wenn ich etwas auffrischen muss
ClassNotFoundException
Klassenhierarchie
ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable
Während des Debuggens
NoClassDefFoundError
Klassenhierarchie
NoClassDefFoundError extends LinkageError extends Error extends Throwable
Während des Debuggens
ClassNotFoundException und NoClassDefFoundError treten auf, wenn eine bestimmte Klasse zur Laufzeit nicht gefunden wird. Sie treten jedoch in verschiedenen Szenarien auf.
ClassNotFoundException ist eine Ausnahme, die auftritt, wenn Sie versuchen, eine Klasse zur Laufzeit mit den Methoden Class.forName () oder loadClass () zu laden, und die genannten Klassen nicht im Klassenpfad gefunden werden.
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 ist ein Fehler, der auftritt, wenn eine bestimmte Klasse zur Kompilierungszeit vorhanden ist, aber zur Laufzeit fehlt.
class A
{
// some code
}
public class B
{
public static void main(String[] args)
{
A a = new A();
}
}
Wenn Sie das obige Programm kompilieren, werden zwei .class-Dateien generiert. Eine ist A.class und eine andere ist B.class. Wenn Sie die A.class-Datei entfernen und die B.class-Datei ausführen, löst Java Runtime System NoClassDefFoundError wie folgt aus:
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)