В этой статье вы узнаете, как JVM загружает классы по мере необходимости, какие бывают загрузчики, почему нельзя подменить String, и откуда берётся ClassNotFoundException. Полезно для junior специалиста.

Когда вы запускаете Java-приложение, JVM не грузит все классы сразу. Она делает это по мере необходимости и именно ClassLoader-ы отвечают за загрузку байткода в память. Давайте разберёмся, как это работает и почему важно понимать эту механику.

Кто такие ClassLoader-ы?

ClassLoader – это часть JVM, которая находит .class-файлы, загружает их в память и создаёт объект Class, который уже можно использовать в программе.

В Java есть три основных загрузчика (можете создать свой):

  • Bootstrap ClassLoader – загружает ядро Java: java.lang.*, включая String, Object и др.

  • Platform ClassLoader (в старых версиях Extension) – отвечает за платформенные модули (например, javax.*).

  • Application ClassLoader – загружает ваши классы, которые находятся в classpath.

Практический пример:

public class Main {
    public static void main(String[] args) {
        MyClass.myMethod();
    }
}
public class MyClass {
    public static void myMethod() {
        System.out.println("Метод myMethod() вызван!");
    }
}

Давайте разберем первый этап работы JVM – загрузку классов. У нас есть простая программа с классом Main, который вызывает метод из класса MyClass.

Что происходит при запуске:

  1. JVM читает наш код и понимает, что для выполнения программы нужны два класса:

    ·        Main (основной класс с методом main)

    ·        MyClass (класс, который используется в программе)

  2. JVM видит строку MyClass.myMethod() и понимает, что нужно найти класс MyClass

  3. JVM запускает процесс Class Loading для загрузки необходимых классов в память

Почему JVM не грузит все классы сразу? Потому что это было бы неэффективно: даже неиспользуемые классы заняли бы память и замедлили запуск. Вместо этого Java применяет ленивую загрузку (lazy class loading) — класс загружается только тогда, когда к нему впервые обращаются. То есть если в нашей программе никогда не происходит обращения к классу MyClass, то JVM его не загрузит — даже если файл MyClass.class физически присутствует в classpath.

Иерархия загрузчиков

Теперь давайте посмотрим на механизм делегирования в ClassLoader-ах. JVM использует иерархическую систему загрузки классов. Каждый загрузчик классов будет искать в своей зоне ответственности. При этом каждый ClassLoader сначала делегирует загрузку своему родителю, и только если родитель не может найти класс, сам начинает поиск.

Последовательность поиска класса MyClass:

  • Application ClassLoader получает запрос на загрузку MyClass

  • Он не ищет сразу в своей области – сначала делегирует запрос Platform ClassLoader

  • Platform ClassLoader тоже не знает, где MyClass – делегирует запрос Bootstrap ClassLoader.

  • Bootstrap ClassLoader ищет в системных библиотеках – там MyClass нет, тогда возвращает null

  • Запрос возвращается обратно из Platform в Application

  • Только теперь Application ClassLoader ищет MyClass в classpath – и находит его!

Для чего нужен такой мудреный механизм поиска? Главная причина – безопасность. Представьте, что создали свой класс java.lang.String с методом stealPassword().

package java.lang;

public class String {
    public static void stealPassword() {
        System.out.println("Пароль украден!");
    }
}

Без делегирования JVM могла бы загрузить его вместо оригинального String. Но благодаря иерархии Bootstrap ClassLoader всегда загружает java.lang. первым – и никто не может его подменить.

А когда возникает ClassNotFoundException?

Если ни один из загрузчиков не смог найти нужный класс, возникает ошибка ClassNotFoundException. По сути, это означает, что ClassLoader не обнаружил соответствующий .class-файл в своей области поиска.

Заключение

В этой статье мы разобрали, как JVM загружает классы: от ленивой загрузки и иерархии ClassLoader-ов до механизма делегирования и защиты критически важных классов вроде java.lang.String. Теперь вы не только понимаете, почему возникает ClassNotFoundException, но и знаете, что происходит «под капотом» уже при запуске простейшей программы.

Это моя первая статья и я очень надеюсь, что она оказалась для вас полезной.