logo

ClassLoader v Javě

Java ClassLoader

Java ClassLoader je abstraktní třída. Patří do a java.lang balík. Načítá třídy z různých zdrojů. Java ClassLoader se používá k načtení tříd za běhu. Jinými slovy, JVM provádí proces propojení za běhu. Třídy se načítají do JVM podle potřeby. Pokud načtená třída závisí na jiné třídě, načte se také. Když požadujeme načtení třídy, deleguje třídu jejímu nadřazenému. Tímto způsobem je v běhovém prostředí zachována jedinečnost. Je nezbytné spustit program Java.

smazat soubor v java
ClassLoader v Javě

Java ClassLoader je založen na třech principech: Delegace , Viditelnost , a Jedinečnost .

    Princip delegování:Předá požadavek na načtení třídy zavaděči nadřazené třídy. Načte třídu pouze v případě, že rodič třídu nenajde nebo nenačte.Princip viditelnosti:Umožňuje zavaděči podřízených tříd vidět všechny třídy načtené nadřazeným ClassLoaderem. Zavaděč nadřazené třídy však nevidí třídy načtené zavaděčem podřízené třídy.Princip jedinečnosti:Umožňuje načíst třídu jednou. Dosahuje se ho principem delegování. Zajišťuje, že podřízený ClassLoader znovu nenačte třídu, která je již načtena rodičem.

Typy ClassLoaderu

V Javě má ​​každý ClassLoader předdefinované umístění, odkud načítá soubory tříd. V Javě existují následující typy ClassLoader:

Zavaděč třídy Bootstrap: Načítá standardní soubory třídy JDK z rt.jar a dalších základních tříd. Je to rodič všech zavaděčů třídy. Nemá žádného rodiče. Když zavoláme String.class.getClassLoader(), vrátí hodnotu null a jakýkoli kód založený na ní vyvolá výjimku NullPointerException. Říká se mu také Primordial ClassLoader. Načítá soubory tříd z jre/lib/rt.jar. Například třída balíčku java.lang.

Zavaděč třídy rozšíření: Deleguje požadavek na načtení třídy na svého rodiče. Pokud je načítání třídy neúspěšné, načte třídy z adresáře jre/lib/ext nebo jakéhokoli jiného adresáře jako java.ext.dirs. Je implementován pomocí sun.misc.Launcher$ExtClassLoader v JVM.

Zavaděč systémové třídy: Načte třídy specifické pro aplikaci z proměnné prostředí CLASSPATH. Lze jej nastavit při spouštění programu pomocí voleb příkazového řádku -cp nebo classpath. Je to potomek Extension ClassLoader. Je implementován třídou sun.misc.Launcher$AppClassLoader. Všechny Java ClassLoader implementují java.lang.ClassLoader.

ClassLoader v Javě

Jak funguje ClassLoader v Javě

Když JVM požaduje třídu, vyvolá metodu loadClass() třídy java.lang.ClassLoader předáním plně klasifikovaného názvu třídy. Metoda loadClass() volá metodu findLoadedClass(), aby zkontrolovala, zda byla třída již načtena nebo ne. Je nutné vyhnout se opakovanému načítání třídy.

Pokud je již třída načtena, deleguje požadavek na nadřazený ClassLoader, aby třídu načetl. Pokud ClassLoader nenachází třídu, vyvolá metodu findClass() k vyhledání tříd v systému souborů. Následující diagram ukazuje, jak ClassLoader načte třídu v Javě pomocí delegování.

ClassLoader v Javě

Předpokládejme, že máme třídu Demo.class specifickou pro aplikaci. Požadavek na načtení souborů této třídy se přenese do Application ClassLoader. Deleguje své nadřazené rozšíření ClassLoader. Dále deleguje Bootstrap ClassLoader. Bootstrap prohledá tuto třídu v rt.jar a protože tam tato třída není. Nyní požádejte o přenos do Extension ClassLoader, který vyhledá adresář jre/lib/ext a pokusí se tam tuto třídu najít. Pokud je zde třída nalezena, Extension ClassLoader načte tuto třídu. Aplikace ClassLoader tuto třídu nikdy nenačte. Když jej rozšíření ClassLoader nenačte, pak jej aplikace ClaasLoader načte z CLASSPATH v Javě.

Princip viditelnosti říká, že podřízený ClassLoader může vidět třídu načtenou nadřazeným ClassLoaderem, ale naopak to neplatí. To znamená, že pokud Application ClassLoader načte Demo.class, v takovém případě pokus načíst Demo.class explicitně pomocí Extension ClassLoader vyvolá výjimku java.lang.ClassNotFoundException.

Podle principu jedinečnosti by třída načtená rodičem neměla být znovu načtena Child ClassLoaderem. Je tedy možné napsat zavaděč třídy, který porušuje principy delegování a jedinečnosti a načte třídu sám.

Stručně řečeno, zavaděč třídy se řídí následujícím pravidlem:

  • Zkontroluje, zda je třída již načtena.
  • Pokud se třída nenačte, požádejte zavaděč nadřazené třídy, aby třídu načetl.
  • Pokud zavaděč nadřazené třídy nemůže načíst třídu, pokuste se ji načíst do tohoto zavaděče třídy.

Zvažte následující příklad:

 public class Demo { public static void main(String args[]) { System.out.println('How are you?'); } } 

Zkompilujte a spusťte výše uvedený kód pomocí následujícího příkazu:

 javac Demo.java java -verbose:class Demo 

-verbose:class: Používá se k zobrazení informací o třídách načítaných JVM. Je to užitečné při použití zavaděče tříd pro dynamické načítání tříd. Následující obrázek ukazuje výstup.

ClassLoader v Javě

Můžeme pozorovat, že nejdříve se načítají runtime třídy požadované třídou aplikace (Demo).

Když jsou načteny třídy

Existují pouze dva případy:

  • Když je proveden nový byte kód.
  • Když bajtový kód vytvoří statický odkaz na třídu. Například, System.out .

Statické vs. dynamické načítání třídy

Třídy jsou staticky načteny operátorem 'nový'. Dynamické načítání třídy vyvolá funkce zavaděče třídy za běhu pomocí metody Class.forName().

Rozdíl mezi loadClass() a Class.forName()

Metoda loadClass() načte pouze třídu, ale neinicializuje objekt. Zatímco metoda Class.forName() inicializuje objekt po jeho načtení. Pokud například používáte ClassLoader.loadClass() k načtení ovladače JDBC, zavaděč třídy nedovolí načíst ovladač JDBC.

Metoda java.lang.Class.forName() vrací objekt třídy spojený s třídou nebo rozhraními s daným názvem řetězce. Pokud třída není nalezena, vyvolá výjimku ClassNotFoundException.

Příklad

V tomto příkladu je načtena třída java.lang.String. Vytiskne název třídy, název balíčku a názvy všech dostupných metod třídy String. V následujícím příkladu používáme Class.forName().

Třída: Představuje objekt třídy, který může být libovolného typu (? je zástupný znak). Typ Class obsahuje metainformace o třídě. Například typ String.class je Class. Použijte Class, pokud je modelovaná třída neznámá.

getDeclaredMethod(): Vrátí pole obsahující objekty Method odrážející všechny deklarované metody třídy nebo rozhraní reprezentované tímto objektem Class, včetně veřejných, chráněných, výchozího (balíčku) přístupu a soukromých metod, ale s výjimkou zděděných metod.

getName(): Vrací název metody reprezentovaný tímto objektem Method jako řetězec.

 import java.lang.reflect.Method; public class ClassForNameExample { public static void main(String[] args) { try { Class cls = Class.forName('java.lang.String'); System.out.println('Class Name: ' + cls.getName()); System.out.println('Package Name: ' + cls.getPackage()); Method[] methods = cls.getDeclaredMethods(); System.out.println('-----Methods of String class -------------'); for (Method method : methods) { System.out.println(method.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 

Výstup

 Class Name: java.lang.String Package Name: package java.lang -----Methods of String class ------------- value coder equals length toString hashCode getChars ------ ------ ------ intern isLatin1 checkOffset checkBoundsOffCount checkBoundsBeginEnd access0 access0