logo

ClassLoader в Java

Java ClassLoader

Java ClassLoader є абстрактним класом. Належить до a java.lang пакет. Він завантажує класи з різних ресурсів. Java ClassLoader використовується для завантаження класів під час виконання. Іншими словами, JVM виконує процес зв'язування під час виконання. Класи завантажуються в JVM відповідно до потреб. Якщо завантажений клас залежить від іншого класу, цей клас також завантажується. Коли ми запитуємо завантаження класу, він делегує клас своєму батьківському. Таким чином зберігається унікальність у середовищі виконання. Виконувати програму на Java необхідно.

приклад даних json
ClassLoader в Java

Java ClassLoader базується на трьох принципах: Делегування , Видимість , і Унікальність .

    Принцип делегування:Він пересилає запит на завантаження класу до завантажувача батьківського класу. Він завантажує клас, лише якщо батько не знаходить і не завантажує клас.Принцип видимості:Це дозволяє дочірньому завантажувачу класів бачити всі класи, завантажені батьківським ClassLoader. Але завантажувач батьківського класу не може бачити класи, завантажені завантажувачем дочірнього класу.Принцип унікальності:Це дозволяє завантажити клас один раз. Це досягається за принципом делегування. Це гарантує, що дочірній ClassLoader не перезавантажить клас, який уже завантажено батьківським.

Типи ClassLoader

У Java кожен ClassLoader має попередньо визначене розташування, звідки вони завантажують файли класу. У Java існують такі типи ClassLoader:

Завантажувач класів Bootstrap: Він завантажує стандартні файли класів JDK з rt.jar та інших основних класів. Він є батьком усіх завантажувачів класів. У нього немає батьків. Коли ми викликаємо String.class.getClassLoader(), він повертає значення null, і будь-який код на його основі викидає NullPointerException. Його також називають Primordial ClassLoader. Він завантажує файли класу з jre/lib/rt.jar. Наприклад, клас пакета java.lang.

Завантажувач класів розширень: Він делегує запит на завантаження класу своєму батькові. Якщо завантаження класу не вдається, він завантажує класи з каталогу jre/lib/ext або будь-якого іншого каталогу як java.ext.dirs. Він реалізований sun.misc.Launcher$ExtClassLoader у JVM.

Завантажувач системного класу: Він завантажує спеціальні класи програми зі змінної середовища CLASSPATH. Його можна встановити під час запуску програми за допомогою параметрів командного рядка -cp або classpath. Це дочірній елемент Extension ClassLoader. Він реалізований класом sun.misc.Launcher$AppClassLoader. Усі Java ClassLoader реалізують java.lang.ClassLoader.

ClassLoader в Java

Як ClassLoader працює в Java

Коли JVM запитує клас, він викликає метод loadClass() класу java.lang.ClassLoader, передаючи повністю класифіковане ім’я класу. Метод loadClass() викликає метод findLoadedClass(), щоб перевірити, чи клас уже завантажено чи ні. Потрібно уникати багаторазового завантаження класу.

Якщо клас уже завантажено, він делегує запит батьківському ClassLoader для завантаження класу. Якщо ClassLoader не знаходить клас, він викликає метод findClass() для пошуку класів у файловій системі. На наступній діаграмі показано, як ClassLoader завантажує клас у Java за допомогою делегування.

ClassLoader в Java

Припустімо, що у нас є спеціальний клас програми Demo.class. Запит на завантаження файлів цього класу передається в Application ClassLoader. Він делегує своєму батьківському Extension ClassLoader. Крім того, він делегує Bootstrap ClassLoader. Bootstrap шукає цей клас у rt.jar, і оскільки цього класу там немає. Тепер надішліть запит на передачу в Extension ClassLoader, який шукає каталог jre/lib/ext і намагається знайти там цей клас. Якщо клас знайдено там, Extension ClassLoader завантажує цей клас. Application ClassLoader ніколи не завантажує цей клас. Якщо розширення ClassLoader не завантажує його, програма ClaasLoader завантажує його з CLASSPATH у Java.

Принцип видимості стверджує, що дочірній ClassLoader може бачити клас, завантажений батьківським ClassLoader, але навпаки не вірно. Це означає, що якщо Application ClassLoader завантажує Demo.class, у такому випадку спроба явно завантажити Demo.class за допомогою Extension ClassLoader викидає java.lang.ClassNotFoundException.

Відповідно до принципу унікальності, клас, завантажений батьківським класом, не повинен повторно завантажуватися Child ClassLoader. Отже, можна написати завантажувач класів, який порушує принципи делегування та унікальності та завантажує клас сам.

Коротше кажучи, завантажувач класів дотримується наступного правила:

  • Він перевіряє, чи клас уже завантажено.
  • Якщо клас не завантажується, попросіть завантажувач батьківського класу завантажити клас.
  • Якщо завантажувач батьківського класу не може завантажити клас, спробуйте завантажити його в цей завантажувач класів.

Розглянемо наступний приклад:

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

Скомпілюйте та запустіть наведений вище код за допомогою такої команди:

 javac Demo.java java -verbose:class Demo 

-verbose:клас: Він використовується для відображення інформації про класи, які завантажуються JVM. Це корисно при використанні завантажувача класів для динамічного завантаження класів. На наступному малюнку показано результат.

ClassLoader в Java

Ми можемо спостерігати, що класи часу виконання, необхідні для класу програми (Demo), завантажуються першими.

Коли завантажуються класи

Є лише два випадки:

  • Коли виконується новий байт-код.
  • Коли байт-код робить статичне посилання на клас. Наприклад, System.out .

Статичне та динамічне завантаження класу

Класи статично завантажуються за допомогою оператора new. Динамічне завантаження класів викликає функції завантажувача класів під час виконання за допомогою методу Class.forName().

Різниця між loadClass() і Class.forName()

Метод loadClass() завантажує лише клас, але не ініціалізує об’єкт. Хоча метод Class.forName() ініціалізує об’єкт після його завантаження. Наприклад, якщо ви використовуєте ClassLoader.loadClass() для завантаження драйвера JDBC, завантажувач класів не дозволяє завантажити драйвер JDBC.

Метод java.lang.Class.forName() повертає об’єкт класу в поєднанні з класом або інтерфейсами з вказаною назвою рядка. Він викидає ClassNotFoundException, якщо клас не знайдено.

приклад

У цьому прикладі завантажено клас java.lang.String. Він друкує назву класу, назву пакета та назви всіх доступних методів класу String. У наступному прикладі ми використовуємо Class.forName().

Клас: Представляє об’єкт Class, який може бути будь-якого типу (? — символ узагальнення). Тип Class містить метаінформацію про клас. Наприклад, тип String.class – це Class. Використовуйте Class, якщо клас, що моделюється, невідомий.

getDeclaredMethod(): Повертає масив, що містить об’єкти Method, які відображають усі оголошені методи класу або інтерфейсу, представленого цим об’єктом Class, включаючи загальнодоступні, захищені, стандартний (пакетний) доступ і приватні методи, але за винятком успадкованих методів.

getName(): Він повертає назву методу, представлену цим об’єктом Method, як рядок.

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

Вихід

 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