Provjera postoji li razred na Javi

1. Pregled

Provjera postojanja klase mogla bi biti korisna pri određivanju koju implementaciju sučelja koristiti. Ova se tehnika obično koristi tijekom starijih postavki JDBC-a.

U ovom vodiču, istražit ćemo nijanse korištenja Class.forName () da provjeri postojanje klase u stazi Java class.

2. Korištenje Class.forName ()

Možemo provjeriti postoji li klasa, posebno koristeći Java Reflection Class.forName (). Iz dokumentacije se vidi da a ClassNotFoundException bit će bačen ako se razred ne može locirati.

2.1. Kada očekivati ClassNotFoundException

Prvo, napišite test koji će sigurno baciti a ClassNotFoundException kako bismo mogli znati da su naši pozitivni testovi sigurni:

@Test (očekuje se = ClassNotFoundException.class) javna praznina givenNonExistingClass_whenUsingForName_thenClassNotFound () baca ClassNotFoundException {Class.forName ("class.that.does.not.exist"); }

Dakle, dokazali smo da će klasa koja ne postoji baciti znak ClassNotFoundException. Napišimo test za razred koji zaista postoji:

@Test javna praznina givenExistingClass_whenUsingForName_thenNoException () baca ClassNotFoundException {Class.forName ("java.lang.String"); }

Ovi testovi to dokazuju trčanje Class.forName () a ne hvatanje a ClassNotFoundException je ekvivalentan navedenoj klasi koja postoji na putu klase. Međutim, ovo nije baš savršeno rješenje zbog nuspojava.

2.2. Nuspojava: Inicijalizacija klase

Bitno je istaknuti da, bez navođenja učitača klase, Class.forName () mora pokrenuti statički inicijalizator na traženoj klasi. To može dovesti do neočekivanog ponašanja.

Da bismo ilustrirali ovo ponašanje, stvorimo klasu koja baca a RuntimeException kada se izvrši njegov statički blok inicijalizatora kako bismo odmah mogli znati kada se izvršava:

javna statička klasa InitializingClass {static {if (true) {// omogućiti bacanje iznimke u statički blok inicijalizacije throw new RuntimeException (); }}}

Vidimo iz zaName () dokumentacija da baca ExceptionInInitializerError ako inicijalizacija izazvana ovom metodom ne uspije.

Napišimo test koji će očekivati ExceptionInInitializerError kada pokušavamo pronaći naš InitializingClass bez navođenja učitača klase:

@Test (očekuje se = ExceptionInInitializerError.class) javna praznina givenInitializingClass_whenUsingForName_thenInitializationError () baca ClassNotFoundException {Class.forName ("path.to.InitializingClass"); }

Budući da je izvršavanje statičkog bloka inicijalizacije klase nevidljiva nuspojava, sada možemo vidjeti kako bi to moglo uzrokovati probleme s izvedbom ili čak pogreške. Pogledajmo kako preskočiti inicijalizaciju razreda.

3. Kazivanje Class.forName () preskočiti inicijalizaciju

Srećom za nas, postoji preopterećena metoda zaName (), koji prihvaća učitavač klase i treba li izvršiti inicijalizaciju klase.

Prema dokumentaciji, sljedeći su pozivi ekvivalentni:

Class.forName ("Foo") Class.forName ("Foo", istina, this.getClass (). GetClassLoader ())

Promjenom pravi do lažno, sada možemo napisati test koji provjerava postoji li naš InitializingClassbez pokretanja njegovog statičkog bloka inicijalizacije:

@Test javna praznina givenInitializingClass_whenUsingForNameWithoutInitialization_thenNoException () baca ClassNotFoundException {Class.forName ("path.to.InitializingClass", false, getClass (). GetClassLoader ()); }

4. Java 9 moduli

Za projekte Java 9+ postoji treće preopterećenje Class.forName (), koji prihvaća a Modul i a Niz naziv klase. Ovo preopterećenje ne pokreće inicijalizator klase prema zadanim postavkama. Također, posebno, vraća se null kada tražena klasa ne postoji, a ne bacanje a ClassNotFoundException.

5. Zaključak

U ovom kratkom vodiču otkrili smo nuspojavu inicijalizacije klase prilikom korištenja Class.forName () i otkrili ste da možete koristiti zaName () preopterećenja da se to ne dogodi.

Izvorni kod sa svim primjerima u ovom vodiču možete pronaći na GitHubu.


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