Первое, что нужно понять, это то, как работает создание объектов на уровне байт-кода.
Как поясняется в JVMS, §3.8. Работа с экземплярами класса:
Экземпляры класса виртуальной машины Java создаются с помощью инструкции new виртуальной машины Java. Напомним, что на уровне виртуальной машины Java конструктор выглядит как метод с именем, предоставленным компилятором <init>
. Этот метод со специальным названием известен как метод инициализации экземпляра (§2.9). Для данного класса может существовать несколько методов инициализации экземпляра, соответствующих нескольким конструкторам. После создания экземпляра класса и инициализации его переменных экземпляра, включая переменные класса и всех его суперклассов, значениями по умолчанию, вызывается метод инициализации экземпляра нового экземпляра класса. Например:
Object create() {
return new Object();
}
компилируется в:
Method java.lang.Object create()
0 new #1 // Class java.lang.Object
3 dup
4 invokespecial #4 // Method java.lang.Object.<init>()V
7 areturn
Таким образом, вызов конструктора через invokespecial
разделяет поведение передачи this
в качестве первого аргумента с invokevirtual
.
Однако следует подчеркнуть, что ссылка на неинициализированную ссылку обрабатывается особым образом, поскольку вам не разрешено использовать ее до вызова конструктора (или суперконструктора, когда вы находитесь внутри конструктора). Это обеспечивается верификатором.
JVMS, §4.10.2.4. Instance Initialization Methods and Newly Created Objects:
… Метод инициализации экземпляра (§2.9) для класса myClass
видит новый неинициализированный объект как аргумент this
в локальной переменной 0. Прежде чем этот метод вызовет другой метод инициализации экземпляра myClass
или его прямого суперкласса в this
, единственная операция метод, который может выполняться на this
, назначает поля, объявленные в myClass
.
При выполнении анализа потока данных в методах экземпляра верификатор инициализирует локальную переменную 0, чтобы она содержала объект текущего класса, или, например, методы инициализации, локальная переменная 0 содержит специальный тип, указывающий на неинициализированный объект. После вызова соответствующего метода инициализации экземпляра (из текущего класса или его прямого суперкласса) для этого объекта все вхождения этого специального типа в модели стека операндов верификатора и в массиве локальных переменных заменяются текущим типом класса. Верификатор отклоняет код, который использует новый объект до того, как он был инициализирован, или который инициализирует объект более одного раза. Кроме того, это гарантирует, что каждый нормальный возврат метода вызывал метод инициализации экземпляра либо в классе этого метода, либо в непосредственном суперклассе.
Точно так же специальный тип создается и помещается в модель стека операндов верификатора в результате инструкции виртуальной машины Java new. Специальный тип указывает инструкцию, с помощью которой был создан экземпляр класса, и тип созданного неинициализированного экземпляра класса. Когда метод инициализации экземпляра, объявленный в классе неинициализированного экземпляра класса, вызывается для этого экземпляра класса, все вхождения специального типа заменяются предполагаемым типом экземпляра класса. Это изменение типа может распространяться на последующие инструкции по мере продолжения анализа потока данных.
Таким образом, код, создающий объект с помощью инструкции new, не может использовать его каким-либо образом до вызова конструктора, тогда как код конструктора может только назначать поля до вызова другого (this(…)
или super(…)
) конструктора. (возможность, используемая внутренними классами для инициализации ссылки на внешний экземпляр в качестве первого действия), но по-прежнему ничего не может сделать со своим неинициализированным this.
Также конструктору не разрешается возвращать значение, когда this
все еще находится в неинициализированном состоянии. Следовательно, автоматически сгенерированный конструктор несет требуемый минимум, вызывая суперконструктор и возвращая значение (на уровне байт-кода неявный возврат отсутствует).
Обычно рекомендуется прочитать Спецификацию виртуальной машины Java® (соответственно его версия Java 11) вместе с к любой конкретной документации или руководствам по ASM.
person
Holger
schedule
09.11.2018