Ответ
Загрузчики классов в Java образуют иерархию с чётким порядком делегирования.
Встроенные загрузчики (Иерархия)
-
Bootstrap ClassLoader (Primordial):
- Назначение: Загружает основные классы Java Core (
java.lang.*,java.util.*и т.д.) изrt.jarи других ключевых библиотек. - Особенность: Реализован на нативном коде (часть JVM), не является Java-объектом. В коде отображается как
null.
- Назначение: Загружает основные классы Java Core (
-
Platform (Extension) ClassLoader:
- Назначение: Загружает классы из директории расширений JRE (например,
jre/lib/ext) или пути, указанного вjava.ext.dirs. - Родитель: Bootstrap ClassLoader.
- Реализация: Java-класс, наследник
java.net.URLClassLoader.
- Назначение: Загружает классы из директории расширений JRE (например,
-
System (Application) ClassLoader:
- Назначение: Загружает классы приложения из classpath (параметр
-cpили-classpath). - Родитель: Platform ClassLoader.
- Реализация: Также наследник
URLClassLoader. Доступен черезClassLoader.getSystemClassLoader().
- Назначение: Загружает классы приложения из classpath (параметр
Пользовательские загрузчики (Custom ClassLoaders)
Разработчик может создавать собственные загрузчики, наследуясь от ClassLoader или URLClassLoader. Это нужно для:
- Динамической загрузки классов (например, из сети или БД).
- Реализации изоляции модулей (как в OSGi или сервлет-контейнерах).
- Hot-swapping кода в runtime.
Пример пользовательского загрузчика:
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 1. Загрузить байт-код класса из нестандартного места
byte[] classBytes = loadClassDataFromCustomSource(name);
if (classBytes == null) {
throw new ClassNotFoundException(name);
}
// 2. Преобразовать байты в Class-объект
return defineClass(name, classBytes, 0, classBytes.length);
}
private byte[] loadClassDataFromCustomSource(String name) { /* ... */ }
}
Принцип делегирования (Parent-Delegation Model)
При запросе на загрузку класса загрузчик сначала делегирует запрос своему родителю. Только если родитель не смог загрузить класс, текущий загрузчик пытается сделать это сам через метод findClass(). Это обеспечивает безопасность и предотвращает загрузку пользовательских классов с именами стандартных (например, java.lang.String).