Class loader

Class loader находит байты класса и создаёт соответствующий объект Class в JVM. Классы загружаются по требованию, поэтому приложение не обязано читать весь classpath при старте.

Этапы работы с классом

  1. Loading — поиск байтов и создание Class.
  2. Linking:
    • verification проверяет корректность байт-кода;
    • preparation выделяет память статическим полям и задаёт значения по умолчанию;
    • resolution связывает символические ссылки, иногда лениво.
  3. 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.

Вопросы для собеседования

  1. Когда класс инициализируется? При первом активном использовании: создании объекта, вызове static-метода или чтении не compile-time-константы.
  2. Что такое parent delegation? Сначала поиск делегируется родителю.
  3. Почему нельзя подменить java.lang.String? Его загрузку забирает bootstrap loader, а пакеты платформы защищены.
  4. Чем ClassNotFoundException отличается от NoClassDefFoundError? Первая обычно возникает при явной загрузке, вторая — при линковке/исполнении.
  5. Что определяет тип класса? Имя вместе с экземпляром class loader.
  6. Зачем собственный загрузчик? Для плагинов, изоляции версий или загрузки байт-кода из нестандартного источника.