389 Stimmen

Was sind die Ursachen und Unterschiede zwischen NoClassDefFoundError und ClassNotFoundException?

Was ist der Unterschied zwischen NoClassDefFoundError y ClassNotFoundException ?

Wodurch werden sie ausgelöst? Wie können sie behoben werden?

Ich stoße oft auf diese Throwables, wenn ich bestehenden Code modifiziere, um neue Jar-Dateien einzubinden. Ich habe sie sowohl auf der Client- als auch auf der Serverseite für eine über Webstart verteilte Java-Anwendung gefunden.

Mögliche Gründe, die ich gefunden habe:

  1. Pakete nicht enthalten in build.xml für die Client-Seite des Codes
  2. Laufzeit-Klassenpfad fehlt für die neuen Jars, die wir verwenden
  3. Versionskonflikte mit früherem jar

Wenn ich heute auf diese Probleme stoße, versuche ich, die Dinge durch Versuch und Irrtum zum Laufen zu bringen. Ich brauche mehr Klarheit und Verständnis.

394voto

coobird Punkte 155882

Der Unterschied zu den Java-API-Spezifikationen ist der folgende.

Para ClassNotFoundException :

Wird ausgelöst, wenn eine Anwendung versucht eine Klasse über ihren String zu laden Namen zu laden:

  • En forName Methode in der Klasse Class .
  • En findSystemClass Methode in der Klasse ClassLoader .
  • En loadClass Methode in der Klasse ClassLoader .

aber keine Definition für die Cla mit dem angegebenen Namen konnte nicht gefunden werden.

Para NoClassDefFoundError :

Wird ausgelöst, wenn die Java Virtual Machine oder a ClassLoader i in die Definition einer Klasse zu laden (als Teil eines normalen Methodenaufrufs oder als Teil von Erzeugung einer neuen Instanz mit dem new Ausdrucks) und keine Definition der Klasse gefunden werden konnte.

Die gesuchte Klassendefinition existierte bereits, als die aktuell ausgeführte Klasse kompiliert wurde, aber die Definition kann nicht mehr gefunden werden.

Es scheint also, dass die NoClassDefFoundError auftritt, wenn der Quellcode erfolgreich kompiliert wurde, aber zur Laufzeit die erforderliche class Dateien wurden nicht gefunden. Dies kann bei der Verteilung oder Produktion von JAR-Dateien vorkommen, wenn nicht alle erforderlichen class Dateien enthalten waren.

In Bezug auf ClassNotFoundException Es scheint, dass es von dem Versuch herrührt, reflektierende Aufrufe an Klassen zur Laufzeit zu machen, aber die Klassen, die das Programm aufzurufen versucht, sind nicht vorhanden.

Der Unterschied zwischen den beiden ist, dass der eine ein Error und der andere ist ein Exception . Mit NoClassDefFoundError ist ein Error und entsteht dadurch, dass die Java Virtual Machine Probleme hat, eine Klasse zu finden, die sie erwartet. Ein Programm, von dem erwartet wurde, dass es zur Kompilierzeit funktioniert, kann nicht ausgeführt werden, weil es class Dateien nicht gefunden werden oder nicht dem entsprechen, was zur Kompilierzeit erzeugt oder angetroffen wurde. Dies ist ein ziemlich kritischer Fehler, da das Programm nicht von der JVM gestartet werden kann.

Auf der anderen Seite ist die ClassNotFoundException ist ein Exception Es ist also etwas, was erwartet wird und was wieder gut gemacht werden kann. Die Verwendung von Reflection kann fehleranfällig sein (da die Erwartung besteht, dass die Dinge nicht wie erwartet ablaufen. Es gibt keine Kompilierzeitprüfung, um zu sehen, ob alle erforderlichen Klassen vorhanden sind, so dass alle Probleme mit der Suche nach den gewünschten Klassen zur Laufzeit auftreten werden.

83voto

Sanjiv Jivan Punkte 1913

Eine ClassNotFoundException wird ausgelöst, wenn die gemeldete Klasse vom ClassLoader nicht gefunden wird. Dies bedeutet normalerweise, dass die Klasse im CLASSPATH fehlt. Es könnte auch bedeuten, dass die betreffende Klasse versucht, von einer anderen Klasse geladen zu werden, die in einem übergeordneten ClassLoader geladen wurde, und daher die Klasse aus dem Child-ClassLoader nicht sichtbar ist. Dies ist manchmal der Fall, wenn man in komplexeren Umgebungen wie einem App Server arbeitet (WebSphere ist berüchtigt für solche Classloader-Probleme).

Die Menschen neigen oft dazu, die java.lang.NoClassDefFoundError con java.lang.ClassNotFoundException Es gibt jedoch einen wichtigen Unterschied. Zum Beispiel eine Ausnahme (eigentlich ein Fehler, da java.lang.NoClassDefFoundError ist eine Unterklasse von java.lang.Error) wie

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

bedeutet nicht, dass sich die Klasse ActiveMQConnectionFactory nicht im CLASSPATH befindet. Das Gegenteil ist der Fall. Es bedeutet, dass die Klasse ActiveMQConnectionFactory vom ClassLoader gefunden wurde, aber beim Versuch, die Klasse zu laden, ein Fehler beim Lesen der Klassendefinition auftrat. Dies geschieht typischerweise, wenn die betreffende Klasse statische Blöcke oder Mitglieder hat, die eine Klasse verwenden, die vom ClassLoader nicht gefunden wird. Um den Schuldigen zu finden, sehen Sie sich den Quellcode der betreffenden Klasse an (in diesem Fall ActiveMQConnectionFactory) und suchen Sie nach Code, der statische Blöcke oder statische Mitglieder verwendet. Wenn Sie keinen Zugriff auf den Quellcode haben, dekompilieren Sie ihn einfach mit JAD.

Bei der Untersuchung des Codes, sagen wir, Sie finden eine Codezeile wie unten, 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 nutzen. Hier können Sie einen Klassennamen mit Platzhaltern angeben und die Klasse wird in der Datenbank der Jars gesucht. jarhoo ermöglicht dasselbe, ist aber nicht mehr kostenlos.

Wenn Sie herausfinden möchten, zu welchem Jar eine Klasse in einem lokalen Pfad gehört, können Sie ein Dienstprogramm wie jarscan ( http://www.inetfeedback.com/jarscan/ ). Sie geben einfach die Klasse an, die Sie suchen möchten, und den Pfad zum Root-Verzeichnis, in dem die Suche nach der Klasse in Jars und Zip-Dateien beginnen soll.

37voto

cletus Punkte 596503

NoClassDefFoundError ist im Grunde ein Verknüpfungsfehler. Er tritt auf, wenn Sie versuchen, ein Objekt zu instanziieren (statisch mit "new") und es nicht gefunden wird, wenn es während der Kompilierung war.

ClassNotFoundException ist allgemeiner und stellt eine Laufzeitausnahme dar, wenn Sie versuchen, eine Klasse zu verwenden, die nicht existiert. Ein Beispiel: Sie haben einen Parameter in einer Funktion, die eine Schnittstelle akzeptiert, und jemand übergibt eine Klasse, die diese Schnittstelle implementiert, aber Sie haben keinen Zugriff auf die Klasse. Sie deckt auch Fälle des dynamischen Ladens von Klassen ab, wie z.B. die Verwendung von loadClass() o Class.forName() .

32voto

mogsie Punkte 3807

Ein NoClassDefFoundError (NCDFE) tritt auf, wenn Ihr Code "new Y()" ausführt und die Klasse Y nicht finden kann.

Es kann einfach sein, dass Y in Ihrem Classloader fehlt, wie die anderen Kommentare andeuten, aber es könnte auch sein, dass die Klasse Y nicht signiert ist oder eine ungültige Signatur hat, oder dass Y von einem anderen Classloader geladen wird, der für Ihren Code nicht sichtbar ist, oder sogar, dass Y von Z abhängt, das aus einem der oben genannten Gründe 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 einen neuen NCDFE, ohne Ihnen zu sagen, warum:

class a {
  static class b {}
  public static void main(String args\[\]) {
    System.out.println("First attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
    System.out.println("\\nSecond attempt new b():");
    try {new b(); } catch(Throwable t) {t.printStackTrace();}
  }
}

Speichern Sie dies als a.java irgendwo

Der Code versucht einfach, eine neue "b"-Klasse zweimal zu instanziieren, ansonsten hat er keine Bugs und tut nichts.

Kompilieren Sie den Code mit javac a.java Dann führen Sie a durch Aufruf von java -cp . a -- es sollten nur zwei Zeilen Text ausgedruckt werden, und es sollte ohne Fehler laufen.

Löschen Sie dann die Datei "a$b.class" (oder füllen Sie sie mit Müll, oder kopieren Sie a.class darüber), um die fehlende oder beschädigte Klasse zu simulieren. Das passiert folgendermaßen:

First attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:5)
Caused by: java.lang.ClassNotFoundException: a$b
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    ... 1 more

Second attempt new b():
java.lang.NoClassDefFoundError: a$b
    at a.main(a.java:7)

Der erste Aufruf führt zu einer ClassNotFoundException (die vom Klassenlader ausgelöst wird, wenn er die Klasse nicht finden kann), die in einen ungeprüften NoClassDefFoundError verpackt werden muss, da der betreffende Code ( new b() ) sollte einfach funktionieren.

Der zweite Versuch wird natürlich auch fehlschlagen, aber wie Sie sehen können, ist die gewickelte Ausnahme nicht mehr vorhanden, da der ClassLoader sich anscheinend an fehlgeschlagene Klassenlader erinnert. Sie sehen nur die NCDFE mit absolut keinem Hinweis darauf, was wirklich passiert ist.

Wenn Sie also jemals einen NCDFE ohne Ursache sehen, müssen Sie sehen, ob Sie die Ursache des Fehlers bis zum ersten Laden der Klasse zurückverfolgen können.

21voto

KingFeming Punkte 1053

En http://www.javaroots.com/2013/02/classnotfoundexception-vs.html :

ClassNotFoundException : tritt auf, wenn der Klassenlader die benötigte Klasse nicht im Klassenpfad finden konnte. Sie sollten also grundsätzlich Ihren Klassenpfad überprüfen und die Klasse in den Klassenpfad aufnehmen.

NoClassDefFoundError : Dies ist schwieriger zu debuggen und den Grund zu finden. Dies wird ausgelöst, wenn zur Kompilierzeit die erforderlichen Klassen vorhanden sind, aber zur Laufzeit die Klassen geändert oder entfernt werden oder die statische Initialisierung der Klasse Ausnahmen auslöst. Es 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.

Exemple :

public class Test1
{
}

public class Test 
{
   public static void main(String[] args)
   {
        Test1 = new Test1();    
   }

}

Wenn Sie nun nach dem Kompilieren der beiden Klassen die Datei Test1.class löschen und die Klasse Test ausführen, wird

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 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, wird dieser Fehler ausgelöst.

NoClassDefFoundError Java Virtual Machine: Wird ausgelöst, wenn die Java Virtual Machine versucht, die Definition einer Klasse zu laden und keine Definition der Klasse gefunden werden konnte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X