logo

ClassLoader în Java

Java ClassLoader

Java ClassLoader este o clasă abstractă. Aparține unui java.lang pachet. Încarcă clase din diferite resurse. Java ClassLoader este folosit pentru a încărca clasele în timpul rulării. Cu alte cuvinte, JVM realizează procesul de conectare în timpul execuției. Clasele sunt încărcate în JVM în funcție de nevoi. Dacă o clasă încărcată depinde de o altă clasă, acea clasă este încărcată de asemenea. Când solicităm încărcarea unei clase, aceasta deleagă clasa părintelui său. În acest fel, unicitatea este menținută în mediul de rulare. Este esențial să executați un program Java.

convertiți nfa în dfa
ClassLoader în Java

Java ClassLoader se bazează pe trei principii: Delegație , Vizibilitate , și Unicitatea .

    Principiul delegării:Redirecționează cererea de încărcare a clasei către încărcătorul de clasă părinte. Încarcă clasa doar dacă părintele nu găsește sau încarcă clasa.Principiul vizibilității:Permite încărcării claselor copil să vadă toate clasele încărcate de ClassLoader părinte. Dar încărcătorul de clasă părinte nu poate vedea clasele încărcate de încărcătorul de clasă copil.Principiul unicității:Permite încărcarea unei clase o dată. Se realizează prin principiul delegării. Se asigură că ClassLoader copil nu reîncarcă clasa, care este deja încărcată de părinte.

Tipuri de ClassLoader

În Java, fiecare ClassLoader are o locație predefinită de unde încarcă fișierele de clasă. Există următoarele tipuri de ClassLoader în Java:

Bootstrap Class Loader: Încarcă fișiere standard de clasă JDK din rt.jar și din alte clase de bază. Este un părinte al tuturor încărcătoarelor de clasă. Nu are niciun părinte. Când apelăm String.class.getClassLoader() returnează null, iar orice cod bazat pe acesta aruncă NullPointerException. Se mai numește și Primordial ClassLoader. Încarcă fișiere de clasă din jre/lib/rt.jar. De exemplu, clasa pachetului java.lang.

Încărcător de clasă de extensii: Deleagă cererea de încărcare a clasei părintelui său. Dacă încărcarea unei clase nu are succes, aceasta încarcă clase din directorul jre/lib/ext sau din orice alt director ca java.ext.dirs. Este implementat de sun.misc.Launcher$ExtClassLoader în JVM.

Încărcător de clasă de sistem: Încarcă clase specifice aplicației din variabila de mediu CLASSPATH. Poate fi setat în timp ce se invocă programul folosind opțiunile de linie de comandă -cp sau classpath. Este un copil al extensiei ClassLoader. Este implementat de clasa sun.misc.Launcher$AppClassLoader. Toate Java ClassLoader implementează java.lang.ClassLoader.

ClassLoader în Java

Cum funcționează ClassLoader în Java

Când JVM solicită o clasă, acesta invocă o metodă loadClass() a clasei java.lang.ClassLoader prin transmiterea numelui complet clasificat al clasei. Metoda loadClass() solicită metoda findLoadedClass() pentru a verifica dacă clasa a fost deja încărcată sau nu. Este necesar să se evite încărcarea clasei de mai multe ori.

Dacă clasa este deja încărcată, aceasta delegă cererea ClassLoader-ului părinte pentru a încărca clasa. Dacă ClassLoader nu găsește clasa, invocă metoda findClass() pentru a căuta clasele în sistemul de fișiere. Următoarea diagramă arată cum ClassLoader încarcă clasa în Java folosind delegarea.

ClassLoader în Java

Să presupunem că avem o clasă specifică aplicației Demo.class. Solicitarea de încărcare a acestor fișiere de clasă se transferă la Application ClassLoader. Acesta delegă către părintele său Extension ClassLoader. În plus, delegă la Bootstrap ClassLoader. Bootstrap caută acea clasă în rt.jar și din moment ce acea clasă nu este acolo. Acum solicitați transferul la Extension ClassLoader care caută directorul jre/lib/ext și încearcă să localizeze această clasă acolo. Dacă clasa este găsită acolo, Extension ClassLoader încarcă acea clasă. Aplicația ClassLoader nu încarcă niciodată acea clasă. Când extensia ClassLoader nu o încarcă, atunci Aplicația ClaasLoader o încarcă din CLASSPATH în Java.

Principiul vizibilității afirmă că ClassLoader copil poate vedea clasa încărcată de ClassLoader părinte, dar invers nu este adevărat. Înseamnă că, dacă Application ClassLoader încarcă Demo.class, în acest caz, încercarea de a încărca Demo.class în mod explicit folosind Extension ClassLoader aruncă java.lang.ClassNotFoundException.

Conform principiului unicității, o clasă încărcată de părinte nu ar trebui să fie încărcată din nou de Child ClassLoader. Deci, este posibil să scrieți clasa de încărcare care încalcă principiile de delegare și unicitate și să încarce clasa de la sine.

Pe scurt, clasa de încărcare urmează următoarea regulă:

  • Verifică dacă clasa este deja încărcată.
  • Dacă clasa nu este încărcată, cereți încărcării clasei părinte să încarce clasa.
  • Dacă încărcătorul de clasă părinte nu poate încărca clasa, încercați să o încărcați în acest încărcător de clasă.

Luați în considerare următorul exemplu:

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

Compilați și rulați codul de mai sus utilizând următoarea comandă:

 javac Demo.java java -verbose:class Demo 

-verbose:class: Este folosit pentru a afișa informații despre clasele încărcate de JVM. Este util atunci când utilizați class loader pentru încărcarea dinamică a claselor. Figura următoare arată rezultatul.

ClassLoader în Java

Putem observa că clasele de rulare cerute de clasa aplicației (Demo) sunt încărcate mai întâi.

Când clasele sunt încărcate

Există doar două cazuri:

  • Când este executat noul cod octet.
  • Când codul octet face o referire statică la o clasă. De exemplu, System.out .

Încărcare de clasă statică vs. dinamică

Clasele sunt încărcate static cu operatorul „nou”. Încărcarea dinamică a clasei invocă funcțiile unui încărcător de clasă în timpul rulării utilizând metoda Class.forName().

Diferența dintre loadClass() și Class.forName()

Metoda loadClass() încarcă numai clasa, dar nu inițializează obiectul. În timp ce metoda Class.forName() inițializează obiectul după încărcarea acestuia. De exemplu, dacă utilizați ClassLoader.loadClass() pentru a încărca driverul JDBC, încărcătorul de clasă nu permite încărcarea driverului JDBC.

Metoda java.lang.Class.forName() returnează obiectul Class cuplat cu clasa sau interfețele cu numele șirului dat. Aruncă ClassNotFoundException dacă clasa nu este găsită.

Exemplu

În acest exemplu, clasa java.lang.String este încărcată. Tipărește numele clasei, numele pachetului și numele tuturor metodelor disponibile ale clasei String. Folosim Class.forName() în exemplul următor.

Clasă: Reprezintă un obiect Class care poate fi de orice tip (? este un wildcard). Tipul Class conține metainformații despre o clasă. De exemplu, tipul String.class este Class. Folosiți Class dacă clasa modelată este necunoscută.

getDeclaredMethod(): Returnează o matrice care conține obiecte Method care reflectă toate metodele declarate ale clasei sau interfeței reprezentate de acest obiect Class, inclusiv metodele publice, protejate, acces implicit (pachet) și private, dar excluzând metodele moștenite.

getName(): Returnează numele metodei reprezentat de acest obiect Method, ca șir.

 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(); } } } 

Ieșire

 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