ClassNotFoundException vs NoClassDefFoundError

1. Einleitung

Sowohl ClassNotFoundException als auch NoClassDefFoundError treten auf, wenn die JVM keine angeforderte Klasse im Klassenpfad finden kann. Obwohl sie vertraut aussehen, gibt es einige wesentliche Unterschiede zwischen diesen beiden.

In diesem Tutorial werden wir einige der Gründe für ihr Auftreten und ihre Lösungen diskutieren.

2. ClassNotFoundException

ClassNotFoundException ist eine geprüfte Ausnahme, die auftritt, wenn eine Anwendung versucht, eine Klasse über ihren vollständig qualifizierten Namen zu laden, und ihre Definition im Klassenpfad nicht finden kann.

Dies tritt hauptsächlich auf, wenn versucht wird, Klassen mit Class.forName () , ClassLoader.loadClass () oder ClassLoader.findSystemClass () zu laden . Daher müssen wir bei der Arbeit mit Reflektion besonders vorsichtig mit java.lang.ClassNotFoundException sein .

Versuchen wir beispielsweise, die JDBC-Treiberklasse zu laden, ohne die erforderlichen Abhängigkeiten hinzuzufügen, die uns ClassNotFoundException bringen:

@Test(expected = ClassNotFoundException.class) public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() throws ClassNotFoundException { Class.forName("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError ist ein schwerwiegender Fehler. Es tritt auf, wenn JVM die Definition der Klasse nicht finden kann, während versucht wird:

  • Instanziieren Sie eine Klasse mit dem neuen Schlüsselwort
  • Laden Sie eine Klasse mit einem Methodenaufruf

Der Fehler tritt auf, wenn ein Compiler die Klasse erfolgreich kompilieren konnte, die Java-Laufzeit die Klassendatei jedoch nicht finden konnte. Dies tritt normalerweise auf, wenn beim Ausführen eines statischen Blocks oder beim Initialisieren statischer Felder der Klasse eine Ausnahme auftritt, sodass die Klasseninitialisierung fehlschlägt.

Betrachten wir ein Szenario, das eine einfache Möglichkeit darstellt, das Problem zu reproduzieren. Die Initialisierung von ClassWithInitErrors löst eine Ausnahme aus. Wenn wir also versuchen, ein Objekt von ClassWithInitErrors zu erstellen , wird ExceptionInInitializerError ausgelöst .

Wenn wir versuchen, dieselbe Klasse erneut zu laden, erhalten wir den NoClassDefFoundError:

public class ClassWithInitErrors { static int data = 1 / 0; }
public class NoClassDefFoundErrorExample { public ClassWithInitErrors getClassWithInitErrors() { ClassWithInitErrors test; try { test = new ClassWithInitErrors(); } catch (Throwable t) { System.out.println(t); } test = new ClassWithInitErrors(); return test; } }

Lassen Sie uns einen Testfall für dieses Szenario schreiben:

@Test(expected = NoClassDefFoundError.class) public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() { NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample(); sample.getClassWithInitErrors(); }

4. Auflösung

Manchmal kann es ziemlich zeitaufwändig sein, diese beiden Probleme zu diagnostizieren und zu beheben. Der Hauptgrund für beide Probleme ist die Nichtverfügbarkeit der Klassendatei (im Klassenpfad) zur Laufzeit.

Werfen wir einen Blick auf einige Ansätze, die wir in Betracht ziehen können, wenn wir uns mit einem dieser beiden befassen:

  1. Wir müssen sicherstellen, dass eine Klasse oder ein Glas, das diese Klasse enthält, im Klassenpfad verfügbar ist. Wenn nicht, müssen wir es hinzufügen
  2. Wenn es im Klassenpfad der Anwendung verfügbar ist, wird der Klassenpfad höchstwahrscheinlich überschrieben. Um dies zu beheben, müssen wir den genauen Klassenpfad finden, der von unserer Anwendung verwendet wird
  3. Wenn eine Anwendung mehrere Klassenlader verwendet, sind von einem Klassenlader geladene Klassen möglicherweise nicht für andere Klassenlader verfügbar. Um das Problem gut zu beheben, ist es wichtig zu wissen, wie Klassenladeprogramme in Java funktionieren

5. Zusammenfassung

Diese beiden Ausnahmen beziehen sich auf Klassenpfad und Java-Laufzeit, die zur Laufzeit keine Klasse finden können. Es ist jedoch wichtig, ihre Unterschiede zu beachten.

Die Java-Laufzeit löst ClassNotFoundException aus, während versucht wird, eine Klasse nur zur Laufzeit zu laden, und der Name wurde zur Laufzeit angegeben. Im Fall von NoClassDefFoundError war die Klasse zur Kompilierungszeit vorhanden, aber die Java-Laufzeit konnte sie zur Laufzeit nicht im Java-Klassenpfad finden.

Wie immer finden Sie den vollständigen Code für alle Beispiele auf GitHub.