Жизненный цикл класса
Класс проходит три фазы. Loading — class loader находит и читает байткод .class, создаёт объект Class в metaspace. Linking делится на verification (проверка корректности и безопасности байткода), preparation (выделение статических полей со значениями по умолчанию) и resolution (разрешение символьных ссылок). Initialization — выполнение статических инициализаторов и присваивание статических полей.
Разделение важно: на preparation static int x уже существует со значением 0, а реальное значение из объявления присваивается только на initialization.
Иерархия загрузчиков и делегирование
Загрузчики образуют цепочку: bootstrap (ядро JDK, java.base), platform и application (classpath приложения). По умолчанию работает parent-first delegation: загрузчик сначала просит родителя загрузить класс и берётся за дело сам, только если тот не смог.
Это защищает от подмены системных классов (нельзя подсунуть свой java.lang.String) и обеспечивает, что один и тот же системный класс не загрузится дважды.

Когда класс инициализируется
Инициализация ленивая и происходит при первом активном использовании: создание экземпляра, обращение к статическому полю (не константе времени компиляции), вызов статического метода, рефлексия. Простое объявление ссылки на тип класс не инициализирует.
Инициализация потокобезопасна: JVM гарантирует, что статический инициализатор выполнится один раз даже при гонке потоков — на этом основан, например, идиом «holder» для ленивого синглтона.
class Holder { static final Config C = load(); } // инициализируется
// лениво и потокобезопасно при первом обращении к Holder.C
Идентичность класса и изоляция
Класс в рантайме идентифицируется парой (полное имя + загрузчик). Один и тот же .class, загруженный двумя разными загрузчиками, — это два разных типа, и присваивание между ними даст ClassCastException.
На этом строится изоляция: серверы приложений и плагинные системы дают каждому модулю свой загрузчик, чтобы их зависимости не конфликтовали.
Типичные проблемы
ClassNotFoundException — класс не найден при динамической загрузке (рефлексия), это checked-исключение. NoClassDefFoundError — класс был при компиляции, но отсутствует/не загрузился в рантайме (или упала его инициализация ранее) — это Error.
Различать их полезно: первое почти всегда про classpath/имя, второе часто про сломанную инициализацию или несовпадение версий.
Как отвечать на собеседовании
Разложите loading/linking(verify/prepare/resolve)/initialization, объясните parent-first delegation и зачем оно (безопасность системных классов), назовите триггеры ленивой инициализации и её потокобезопасность (holder-синглтон), и различите ClassNotFoundException и NoClassDefFoundError.