ClassLoader в Java: кто загружает классы
💻 Информатика · 11 класс
Делегирование, имя класса и различие между загрузкой и инициализацией.

Что делает загрузчик
ClassLoader отвечает за поиск или получение определения класса и создание связанного представления в виртуальной машине. Обычно он работает с байт-кодом .class, но источник может быть не только обычным файлом. Загрузчик не является компилятором: он не обязан переводить исходный .java в байт-код.
Важно различать загрузку, связывание и инициализацию. Получить описание класса ещё не значит обязательно выполнить его статические инициализаторы. Имена этих этапов нельзя использовать как синонимы.
Делегирование
Стандартная реализация loadClass сначала проверяет уже загруженный класс, затем обычно обращается к родительскому загрузчику и только после неудачи ищет собственным способом. Так поддерживается согласованность базовых типов. Пользовательские загрузчики могут менять стратегию, поэтому схема «каждый загрузчик всегда только так работает» слишком категорична.
В современных JDK различают bootstrap, platform и application class loaders. Bootstrap реализован особым образом; вызов getClassLoader у некоторых базовых классов может вернуть null. Это не означает, что String не был загружен вообще.
Разобранное наблюдение
System.out.println(String.class.getClassLoader());
System.out.println(MyApp.class.getClassLoader());В обычном запуске String связан с bootstrap, поэтому первая строка может показать null. Для MyApp, определённого как класс вашего приложения, обычно будет показан загрузчик приложения. Точный вид второй строки зависит от JDK и окружения; нельзя требовать одинаковый адрес объекта на всех компьютерах.
Для эксперимента поместите обе строки внутрь main класса MyApp и запускайте обычным способом. В среде модулей, контейнере или приложении с пользовательскими загрузчиками результат требует отдельного объяснения.
Почему одного имени недостаточно
В идентичности загруженного класса участвует не только двоичное имя, но и определивший его загрузчик. Поэтому две копии одинаково названного типа, загруженные разными определяющими загрузчиками, могут быть разными типами. Это важно для плагинов и серверных сред: совпадение текста имени не гарантирует успешного приведения.
Поиск и инициализация
Вызов Class.forName(name) в обычной форме инициирует инициализацию найденного класса. У перегрузок есть параметры, позволяющие управлять этим поведением. Вызов loader.loadClass(name) не следует описывать как обещание немедленного выполнения всей статической логики класса.
Задания
- Почему null в String.class.getClassLoader() не означает отсутствия класса?
- Может ли совпадение имени двух классов гарантировать их тождество?
- Какая ошибка в утверждении «ClassLoader компилирует Java-исходники»?
Ответы
1. Так может обозначаться bootstrap-загрузчик. 2. Нет: нужно учитывать определяющий загрузчик. 3. Загрузка определения класса и компиляция .java в .class — разные операции.
Частая ошибка
Не объясняйте любой ClassNotFoundException «поломкой компилятора». Сначала проверьте имя класса, его наличие в доступных источниках и окружение запуска. Для разработки обычного школьного приложения собственный загрузчик чаще не нужен: сначала полезно понять стандартный механизм.