В каком порядке инициализируются различные части класса при загрузке класса в JVM?

представьте себе класс Java, который имеет большинство функций, которые вы можете найти в классе. Например: он наследует от другого класса, реализует пару интерфейсов, включает некоторые "статические конечные" константы, некоторые конечные константы, некоторые статические переменные, переменные экземпляра, статический блок, неназванный блок кода (просто код в {}), конструкторы, методы и т. д.

когда рассматриваемый класс загружается в JVM в первый раз, в каком порядке различные части класса инициализирован или загружен в JVM? Как выглядит стек вызовов в JVM для загрузки? Предположим, что здесь работает только один classloader.

Это возвращается к абсолютным основам / внутренностям Java, но я не смог найти хорошую статью, объясняющую правильную последовательность.

2 ответов


как о JLS, в частности раздел 12.4?


это можно описать в разделе 2.17.4 СПМ 5.0 / 6

инициализации 2.17.4

инициализация класса состоит из:

  • выполнение статических инициализаторов (§2.11) и
  • инициализаторы для статических полей (§2.9.2), объявленных в классе.

инициализация интерфейса состоит из выполнения инициализаторов для полей, объявленных в интерфейсе (§2.13.3.1).

перед инициализацией класса или интерфейса необходимо инициализировать его прямой суперкласс, но интерфейсы, реализованные классом, инициализироваться не нужно. Аналогично, суперинтерфейсы интерфейса не должны инициализироваться до инициализации интерфейса.

класс или тип интерфейса T будет инициализирован непосредственно перед одним из следующих событий:

  • T-класс и экземпляр T создаваемый.
  • T является классом, и вызывается статический метод T.
  • используется или назначается нестационарное статическое поле T. Поле константы-это поле, которое (явно или неявно) является окончательным и статическим и инициализируется значением выражения константы времени компиляции. Ссылка на такое поле должна быть разрешена во время компиляции для копии значения константы времени компиляции, поэтому использование такого поля никогда не вызывает инициализации.

вызов определенных методов в классах библиотеки (§3.12) также вызывает инициализацию класса или интерфейса. См. спецификации библиотеки классов платформы Java 2 (например, Class Class и package java.ленг.отражения) для деталей.

намерение здесь состоит в том, что тип имеет набор инициализаторов, которые помещают его в согласованное состояние, и что это состояние является первым состоянием, которое наблюдается другими классами. Статические инициализаторы и инициализаторы переменных класса выполняются в текстовом порядке и не может ссылаться на переменные класса, объявленные в классе, чьи объявления появляются дословно После использования, даже если эти переменные класса находятся в области. Это ограничение предназначено для обнаружения во время компиляции большинства циклических или иным образом искаженных инициализаций.

перед инициализацией класса или интерфейса инициализируется его суперкласс, если он ранее не был инициализирован.


обновленная версия инициализация в JVMS 8 находится в главе 5.5

инициализация класса или интерфейса состоит в выполнении его метода инициализации класса или интерфейса (§2.9).

класс или интерфейс могут быть инициализированы только в результате:

  • выполнение любой из инструкций виртуальной машины Java new, getstatic, putstatic или invokestatic, который ссылается на класс или интерфейс (§new, §getstatic, §putstatic, §invokestatic).
    Все эти инструкции ссылаются на класс прямо или косвенно через ссылку на поле или ссылку на метод.
    При выполнении новой инструкции ссылочный класс или интерфейс инициализируется, если он еще не был инициализирован.
    При исполнении getstatic, putstatic или invokestatic обучение, класс или интерфейс, который объявил разрешенное поле или метод инициализируется, если он еще не был инициализирован.
  • первый вызов java.lang.invoke.MethodHandle экземпляр, который был результатом разрешения дескриптора метода виртуальной машиной Java (5.4.3.5§) и который имеет вид 2 (REF_getStatic), 4 (REF_putStatic), 6 (REF_invokeStatic) или 8 (REF_newInvokeSpecial).
  • вызов некоторых отражающих методов в библиотеке классов (§2.12), например, в классе Class или в пакет java.lang.reflect.
  • инициализация одного из его подклассов.
  • его обозначение в качестве начального класса при запуске виртуальной машины Java (§5.2).

перед инициализацией класс или интерфейс должны быть связаны, то есть проверены, подготовлены и необязательно разрешены.

поскольку виртуальная машина Java многопоточна, инициализация класса или интерфейса требует осторожного синхронизация, так как какой-то другой поток может пытаться инициализировать тот же класс или интерфейс одновременно.
Существует также возможность, что инициализация класса или интерфейса может быть запрошена рекурсивно как часть инициализации класса или интерфейса.

реализация виртуальной машины Java отвечает за заботу о синхронизации и рекурсивной инициализации с помощью следующей процедуры.
Предполагается, что the Class объект уже проверен и подготовлен, и что Class объект содержит состояние, указывающее на одну из четырех ситуаций:

  • этой Class объект проверен и подготовлен, но не инициализирован.
  • этой Class объект инициализируется каким-то конкретным потоком.
  • этой Class объект полностью инициализирован и готов к использованию.
  • этой Class "объект" находится в ошибочном состоянии, возможно потому что инициализация была предпринята и не удалось.