Class loader
Class loader находит байты класса и создаёт соответствующий объект Class
в JVM. Классы загружаются по требованию, поэтому приложение не обязано читать
весь classpath при старте.
Этапы работы с классом
- Loading — поиск байтов и создание
Class. - Linking:
- verification проверяет корректность байт-кода;
- preparation выделяет память статическим полям и задаёт значения по умолчанию;
- resolution связывает символические ссылки, иногда лениво.
- Initialization — выполняются статические инициализаторы и присваивания.
class Settings {
static final int PORT = readPort();
static int readPort() {
System.out.println("initialize");
return 8080;
}
}Обращение к Settings.PORT инициирует класс. Простая ссылка на
Settings.class не обязана выполнять его статический код.
Встроенная иерархия Java 9+
| Загрузчик | Что загружает |
|---|---|
| Bootstrap | ключевые модули runtime, включая java.base |
| Platform | платформенные модули, не относящиеся к bootstrap |
| Application | классы приложения с classpath или module path |
Старый Extension Class Loader после появления модульной системы заменён
Platform Class Loader. Bootstrap реализован внутри JVM и в Java-коде может
быть представлен значением null.
Делегирование
Обычно действует parent-first: загрузчик сначала просит родителя и только после неудачи ищет класс сам. Это защищает базовые классы от подмены. Контейнеры и plugin-системы иногда применяют child-first для изоляции зависимостей, но тогда возрастает риск конфликтов.
Идентичность класса — пара «полное имя + загрузивший class loader». Два класса
с одинаковым байт-кодом, загруженные разными загрузчиками, несовместимы:
приведение может закончиться ClassCastException.
Ошибки
ClassNotFoundException— явный поиск, напримерClass.forName, не нашёл класс;NoClassDefFoundError— класс был нужен JVM, но недоступен или не инициализировался;ExceptionInInitializerError— упал статический инициализатор;- утечка class loader — долгоживущая ссылка удерживает загрузчик и все его классы.
Связь с модулями: Структура JDK. Размещение метаданных: Стек и куча в Java.
Вопросы для собеседования
- Когда класс инициализируется? При первом активном использовании: создании объекта, вызове static-метода или чтении не compile-time-константы.
- Что такое parent delegation? Сначала поиск делегируется родителю.
- Почему нельзя подменить
java.lang.String? Его загрузку забирает bootstrap loader, а пакеты платформы защищены. - Чем
ClassNotFoundExceptionотличается отNoClassDefFoundError? Первая обычно возникает при явной загрузке, вторая — при линковке/исполнении. - Что определяет тип класса? Имя вместе с экземпляром class loader.
- Зачем собственный загрузчик? Для плагинов, изоляции версий или загрузки байт-кода из нестандартного источника.