ClassNotFoundException vs NoClassDefFoundError

1. Introduktion

Begge ClassNotFoundException og NoClassDefFoundError opstå, når JVM ikke kan finde en anmodet klasse på klassestien. Selvom de ser velkendte ud, er der nogle vigtige forskelle mellem disse to.

I denne vejledning diskuterer vi nogle af årsagerne til deres forekomster og deres løsninger.

2. ClassNotFoundException

ClassNotFoundException er en kontrolleret undtagelse, der opstår, når et program forsøger at indlæse en klasse gennem sit fuldt kvalificerede navn og ikke kan finde sin definition på klassestien.

Dette sker hovedsageligt når man prøver at indlæse klasser ved hjælp af Class.forName (), ClassLoader.loadClass () eller ClassLoader.findSystemClass (). Derfor skal vi være ekstra forsigtige med java.lang.ClassNotFoundException mens du arbejder med refleksion.

Lad os for eksempel prøve at indlæse JDBC-førerklassen uden at tilføje nødvendige afhængigheder, der får os ClassNotFoundException:

@Test (forventet = ClassNotFoundException.class) offentlig ugyldighed givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException () kaster ClassNotFoundException {Class.forName ("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError er en fatal fejl. Det sker, når JVM ikke kan finde definitionen af ​​klassen, mens de prøver at:

  • Instantiere en klasse ved hjælp af ny nøgleord
  • Indlæs en klasse med et metodekald

Fejlen opstår, når en compiler kunne kompilere klassen, men Java-runtime kunne ikke finde klassefilen. Det sker normalt, når der er en undtagelse under udførelse af en statisk blok eller initialisering af statiske felter i klassen, så klass initialisering mislykkes.

Lad os overveje et scenario, der er en enkel måde at gengive problemet på. ClassWithInitErrors initialisering kaster en undtagelse. Så når vi prøver at skabe et objekt af ClassWithInitErrors, kaster det ExceptionInInitializerError.

Hvis vi prøver at indlæse den samme klasse igen, får vi NoClassDefFoundError:

offentlig klasse ClassWithInitErrors {static int data = 1/0; }
offentlig klasse NoClassDefFoundErrorExample {public ClassWithInitErrors getClassWithInitErrors () {ClassWithInitErrors test; prøv {test = new ClassWithInitErrors (); } fange (Throwable t) {System.out.println (t); } test = ny ClassWithInitErrors (); returprøve }}

Lad os skrive en test case for dette scenarie:

@Test (forventet = NoClassDefFoundError.class) offentlig ugyldighed givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError () {NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample (); sample.getClassWithInitErrors (); }

4. Opløsning

Nogle gange kan det være ret tidskrævende at diagnosticere og løse disse to problemer. Hovedårsagen til begge problemer er klassefilens utilgængelighed (i klassestien) under kørsel.

Lad os se på nogle få tilgange, vi kan overveje, når vi beskæftiger os med en af ​​disse:

  1. Vi er nødt til at sikre os, om klasse eller krukke, der indeholder denne klasse, er tilgængelig på klassestien. Hvis ikke, skal vi tilføje det
  2. Hvis det er tilgængeligt på applikations klassesti, bliver klassesti sandsynligvis tilsidesat. For at rette op på det skal vi finde den nøjagtige klassesti, der bruges af vores applikation
  3. Hvis et program bruger flere klasselæssere, er klasser, der er indlæst af en klasselæsser, muligvis ikke tilgængelige af andre klasselæssere. For at fejlfinde det godt er det vigtigt at vide, hvordan classloaders fungerer i Java

5. Resume

Mens begge disse undtagelser er relateret til classpath og Java runtime, der ikke kan finde en klasse på runtime, er det vigtigt at bemærke deres forskelle.

Java runtime kaster ClassNotFoundException under forsøg på at indlæse en klasse kun ved kørsel, og navnet blev givet under kørsel. I tilfælde af NoClassDefFoundError, den klasse var til stede på kompileringstidspunktet, men Java-runtime kunne ikke finde den i Java-klassesti under runtime.

Som altid kan den komplette kode for alle eksempler findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found