Взяте з цього приємного підручника від Sun:
Мотивація
Програми, написані статично складеними мовами програмування, такими як C та C ++, збираються в рідні, спеціальні для машини інструкції та зберігаються як виконуваний файл. Процес об'єднання коду у виконавчий нативний код називається зв’язуванням - злиттям окремо складеного коду з спільним кодом бібліотеки для створення виконуваної програми. Це відрізняється від динамічно складених мов програмування, таких як Java. У Java файли .class, згенеровані компілятором Java, залишаються такими, що є, поки не завантажуються у віртуальну машину Java (JVM) - іншими словами, процес зв’язку виконується JVM під час виконання. Заняття завантажуються в JVM на основі "за потребою". І коли завантажений клас залежить від іншого класу, тоді і цей клас завантажується.
Коли програма Java запускається, перший клас для запуску (або точка входу в додаток) - це клас із загальнодоступним статичним методом недійсності, який називається main (). Цей клас зазвичай має посилання на інші класи, і всі спроби завантаження посиланих класів здійснює завантажувач класів.
Щоб отримати відчуття цього рекурсивного завантаження класу, а також ідеї завантаження класу загалом, розгляньте наступний простий клас:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
Якщо ви запустите цей клас із зазначенням параметра командного рядка -verbose: class, щоб він друкував, які класи завантажуються, ви отримаєте вихід, який виглядає наступним чином. Зауважте, що це лише частковий вихід, оскільки тут список занадто довгий для показу.
prmpt>java -verbose:class HelloApp
[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
Як бачите, спочатку завантажуються класи виконання Java, необхідні класу додатків (HelloApp).
Навантажувачі класів на платформі Java 2
Мова програмування Java постійно розвивається, щоб полегшити життя розробників додатків щодня. Це робиться шляхом надання API, які спрощують ваше життя, дозволяючи сконцентруватися на бізнес-логіці, а не на деталях впровадження основних механізмів. Це очевидно недавньою зміною J2SE 1.5 на J2SE 5.0 з метою відображення зрілості платформи Java.
Станом на JDK 1.2, завантажувач класів завантажувального класу, вбудований у JVM, відповідає за завантаження класів виконання Java. Цей завантажувач класів завантажує лише класи, які знаходяться у завантажувальному класі, і оскільки це довірені класи, процес перевірки не виконується, як для ненадійних класів. Окрім завантажувача класу завантаження, JVM має завантажувач класів розширень, відповідальний за завантаження класів із стандартних API розширень, та завантажувач системного класу, який завантажує класи як із загального шляху до класів, так і з ваших класів додатків.
Оскільки завантажувач класів більше, ніж вони, вони представлені у дереві, коренем якого є завантажувач класу завантажувального класу. Кожен завантажувач класів має посилання на свій завантажувач батьківського класу. Коли запитувачу завантажувача класу пропонується завантажити клас, він намагається завантажити його батьківський завантажувач класів перед тим, як спробувати завантажити сам елемент. Батько в свою чергу проконсультується з батьком тощо. Тож лише після того, як усі навантажувачі класів предків не зможуть знайти клас, залучається поточний навантажувач класів. Іншими словами, використовується модель делегування.
Клас java.lang.ClassLoader
Це java.lang.ClassLoader
абстрактний клас, який можна підкласифікувати додатками, яким необхідно розширити спосіб, яким JVM динамічно завантажує класи. Конструктори у java.lang.ClassLoader
(та його підкласах) дозволяють вказати батьків під час інстанціювання нового завантажувача класів. Якщо явно не вказати батьків, завантажувач системного класу віртуальної машини буде призначений як батьківський за замовчуванням. Іншими словами, клас ClassLoader використовує модель делегування для пошуку класів та ресурсів. Отже, кожен екземпляр ClassLoader має пов'язаний завантажувач батьківського класу, так що коли його запитують знайти клас або ресурси, завдання делегується його завантажувачу батьківського класу перед тим, як намагатися знайти сам клас або ресурс. loadClass()
Метод ClassLoader виконує наступні завдання, для того, коли викликається для завантаження класу:
Якщо клас уже завантажений, він повертає його. В іншому випадку він делегує пошук нового класу завантажувачу батьківського класу. Якщо завантажувач батьківського класу не знаходить клас, loadClass()
викликає метод findClass()
пошуку та завантаження класу. У finalClass()
пошуках методу для класу в поточному завантажувач класу , якщо клас ні знайдені батьківським загрузчиком класів.
Докладніше в оригінальній статті, де також показано, як реалізувати власні навантажувачі мережевого класу, яка відповідає на ваше запитання, чому (і як). Дивіться також документи API .