Что является уникальностью загрузки класса в JVM
Что проверяют
Знаете ли вы, чем класс определяется в работающей машине. Вопрос отсеивает тех, для кого класс это просто имя: на стендах с контейнерами, плагинами и перезагрузкой приложений именно это заблуждение порождает самые непонятные ошибки.
Как отвечать
Класс уникален не по имени, а по паре: полное имя и загрузчик, который его определил. Два загрузчика могут прочитать один и тот же байт-код, и получатся два разных типа. Проверка на принадлежность типу вернёт ложь, приведение упадёт, статические поля будут независимыми, а текст ошибки выглядит невозможным: класс нельзя привести к классу с тем же именем.
Отсюда же пакет времени выполнения: он тоже определяется именем вместе с загрузчиком, поэтому доступ на уровне пакета между классами из разных загрузчиков не работает.
Порядок удерживает делегирование родителю. Загрузчик сначала просит загрузить класс родителя и берётся за дело сам, только если тот не смог. Так системные классы всегда приходят из корневого загрузчика и не подменяются своим файлом. Иерархия обычная: корневой, платформенный, загрузчик приложения, дальше пользовательские. Контейнеры приложений часто нарушают порядок и ищут сначала у себя, чтобы приложение видело свою версию библиотеки, и этим же способом создают конфликты.
Стоит разделить этапы: загрузка, связывание с проверкой и разрешением ссылок, инициализация. Инициализация ленивая, выполняется ровно один раз и потокобезопасно, поэтому статический блок и подходит для отложенного создания одиночки.
Где спотыкаются
Отвечают, что класс загружается один раз на всю машину. Один раз он загружается одним загрузчиком, а в приложении с несколькими загрузчиками копий окажется столько же.
Смешивают загрузку и инициализацию. Получить объект класса можно без выполнения статических блоков, а обращение к константе времени компиляции наоборот не инициализирует чужой класс вовсе, хотя выглядит как обращение к нему.
Забывают, что класс выгружается только вместе со своим загрузчиком. Пока где-то остаётся ссылка на объект, созданный старым загрузчиком, весь набор классов жив, и повторные перевыкатки без перезапуска процесса заканчиваются исчерпанием области метаданных.