ClassLoader

Любой класс (экземпляр класса java.lang.Class в среде и .class файл в файловой системе), используемый в среде исполнения был так или иначе загружен каким-либо загрузчиком в Java

Этапы загрузки классов

  1. Загрузка байт-кода из ресурсов и создание экземпляра класса Class. Загрузка базовых классов

  2. Связывание (или линковка)

    1. Verification, происходит проверка корректности полученного байт-кода.

    2. Preparation, выделение оперативной памяти под статические поля и инициализация их значениями по умолчанию.

    3. Resolution, разрешение символьных ссылок типов, полей и методов. Т.е. загрузка классов для типов полей/методов. Может быть в ClassLoader.loadClass(name, boolean resolve) указан способ ленивой загрузки указанных типов (resolve = false)

  3. Инициализация полученного объекта

Стандартные загрузчики

Каждый загрузчик хранит указатель на родительский (Bootstrap -> Extension Classloader -> System Classloader) для того, чтобы смочь делегировать ему загрузку в том случае, если сам будет не в состоянии этого сделать.

Запрос на загрузку класса передается родительскому загрузчику, и попытка загрузить класс самостоятельно выполняется, только если родительский загрузчик не смог найти и загрузить класс.

Загрузчик видит только «свои» классы и классы «родителя» и понятия не имеет о классах, которые были загружены его «потомком».

Загрузка класса опрашивает загрузчики на присутствии загружаемого класса в кэше (в порядке от дочернего класса к родительсскому). А далее в обратном порядке каждый загрузчик пытается загрузить данный класс.

Загрузка классов происходит по мере необходимости определенным загрузчиком, отвечающим за определенную загружаемаю область (rt.jar $JAVA_HOME/lib/ext CLASSPATH)

Bootstrap

Реализован на уровне JVM и не имеет обратной связи со средой исполнения (A.class.getClassLoader() == null для классов из java.*). Данным загрузчиком загружаются классы из директории $JAVA_HOME/lib (rt.jar). Управлять загрузкой базовых классов можно с помощью ключа -Xbootclasspath, который позволяет переопределять наборы базовых классов.

Extension Classloader

Загрузчик расширений. Данный загрузчик загружает классы из директории $JAVA_HOME/lib/ext.

System Classloader

Реализованный на уровне JRE (напр. для SUN JRE sun.misc.Launcher$AppClassLoader). Этим загрузчиком загружаются классы, пути к которым указаны в переменной окружения CLASSPATH. Управлять загрузкой системных классов можно с помощью ключа -classpath или системной опцией java.class.path.

Текущий загрузчик

Текущий загрузчик используется по умолчанию для загрузки классов в процессе исполнения. В часности, при использовании метода Class.forName("")/ClassLoader.loadClass("") или при любой декларации класса, ранее не загруженного.

Каждый класс знает, каким загрузчиком он был загружен, и можно получить эту информацию, вызвав у него метод String.class.getClassLoader()

Для всех классов приложения «текущий» загрузчик, как правило, системный.

Ошибки загрузки классов

ClassNotFoundException

Возникает при динамической загрузке класса во время выполнения программы, когда загрузчики не могут найти требуемый класс ни в кэше, ни по пути нахождения классов.

Например, при использовании рефлексии Class.forName("..."), или же при десериализации объекта с отсутствующим классом.

NoClassDefFoundError

Возникает в том случае, когда во время компиляции искомый класс был доступен, но не виден во время выполнения программы. (Искомое определение класса существовало при компиляции текущего класса, но при исполнении не может быть найдено)