"Верификатор отклоняет код, который использует новый объект до его инициализации."
При проверке байт-кода, поскольку верификатор работает во время компоновки, выводятся типы локальных переменных методов. Типы аргументов метода известны как они есть в сигнатуре метода в файле класса. Типы других локальных переменных неизвестны и выводятся, поэтому я предполагаю, что "использует" в приведенном выше утверждении относится к этому.
EDIT:
Раздел 4.9.4 JVMS гласит:
Метод инициализации экземпляра ( §3.9 ) для класса myClass видит новый неинициализированный объект в качестве аргумента this в локальной переменной 0. До этого метод вызывает другой метод инициализации экземпляра myClass или его прямой суперкласс для этого единственная операция, которую может выполнить метод, - это присвоение полей, объявленных в myClass.
Это назначение полей в вышеприведенном выражении является «начальной» инициализацией переменных экземпляра начальными значениями по умолчанию (например, int равно 0, float равно 0.0f и т. Д.), Когда выделяется память для объекта. Существует еще одна «правильная» инициализация переменных экземпляра, когда виртуальная машина вызывает метод инициализации экземпляра (конструктор) для объекта.
ссылка , предоставленная Джоном Хорстманном, помогла уточнить вещи.
Так что эти утверждения не верны. «Это НЕ означает, что в <init>
методе getfield
и putfield
разрешены до вызова другого <init>
».
Инструкции getfield
и putfield
используются для доступа (и изменения) переменных (полей) экземпляра класса (или экземпляра класса). И это может произойти, только когда переменные экземпляра (поля) инициализированы. "
Из JVMS:
Каждый метод инициализации экземпляра
(§3.9), за исключением случая
метод инициализации, полученный из
конструктор класса Object, должен
вызвать другой экземпляр
метод инициализации этого или
метод инициализации экземпляра его
прямой суперкласс супер перед его
Доступ к членам экземпляра
Тем не менее, поля экземпляра этого, что
объявлены в текущем классе может
быть назначенным до вызова любого
метод инициализации экземпляра.
Когда виртуальная машина Java создает новый экземпляр класса, неявно или явно, он сначала выделяет память в куче для хранения переменных экземпляра объекта. Память выделяется для всех переменных, объявленных в классе объекта и во всех его суперклассах, включая скрытые переменные экземпляра. Как только виртуальная машина выделяет кучу памяти для нового объекта, она немедленно инициализирует переменные экземпляра начальными значениями по умолчанию. Как только виртуальная машина выделит память для нового объекта и инициализирует переменные экземпляра значениями по умолчанию, она готова присвоить переменным экземпляра их правильные начальные значения. Виртуальная машина Java использует для этого два метода, в зависимости от того, создается ли объект из-за вызова clone (). Если объект создается из-за clone (), виртуальная машина копирует значения переменных экземпляра объекта, клонируемого в новый объект. В противном случае виртуальная машина вызывает метод инициализации экземпляра объекта. Метод инициализации экземпляра инициализирует переменные экземпляра объекта их правильными начальными значениями. И только после этого вы можете использовать getfield
и putfield
.
ThКомпилятор Java генерирует по крайней мере один метод инициализации экземпляра (конструктор) для каждого класса, который он компилирует. Если класс явно не объявляет конструкторов, компилятор генерирует конструктор по умолчанию без аргументов, который просто вызывает конструктор суперкласса без аргументов. И правильно, если любая операция над полем экземпляра перед вызовом super()
или this()
приведет к ошибке компиляции.
Метод <init>
может содержать три вида кода: вызов другого метода <init>
, код, который реализует любые инициализаторы переменных экземпляра, и код для тела конструктора. Если конструктор начинается с явного вызова другого конструктора в том же классе (вызов this()
), соответствующий ему метод <init>
будет состоять из двух частей:
- вызов того же класса
<init>
метод
- байт-коды, которые реализуют тело
соответствующего конструктора
Если конструктор не начинается с вызова this()
и класс не является объектом, метод <init>
будет иметь три компонента:
- вызов суперкласса
<init>
метод
- байт-коды для любого экземпляра
инициализаторы переменных
- байт-коды, которые реализуют тело
соответствующего конструктора
Если конструктор не начинается с вызова this()
, а класс - Object (а Object не имеет суперкласса), то его метод <init>
не может начинаться с вызова метода суперкласса <init>
.
Если конструктор начинается с явного вызова конструктора суперкласса (вызов super()
), его метод <init>
вызовет соответствующий метод <init>
суперкласса.
Я думаю, что это отвечает на ваш первый и второй вопрос.
Обновлен:
Например,
class Demo
{
int somint;
Demo() //first constructor
{
this(5);
//some other stuff..
}
Demo(int i) //second constructor
{
this.somint = i;
//some other stuff......
}
Demo(int i, int j) //third constructor
{
super();
//other stuffff......
}
}
Вот байт-код для трех вышеупомянутых конструкторов из компилятора (javac):
Demo();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: iconst_5
2: invokespecial #1; //Method "<init>":(I)V
5: return
Demo(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: invokespecial #2; //Method java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #3; //Field somint:I
9: return
Demo(int, int);
Code:
Stack=1, Locals=3, Args_size=3
0: aload_0
1: invokespecial #2; //Method java/lang/Object."<init>":()V
4: return
В первом конструкторе метод <init>
начинается с вызова метода <init>
того же класса, а затем выполняется тело соответствующего конструктора. Поскольку конструктор начинается с this()
, соответствующий ему метод <init>
не содержит байт-кода для инициализации переменных экземпляра.
Во втором конструкторе метод <init>
для конструктора имеет
- метод суперкласса
<init>
, т. Е.
вызов суперкласса
конструктор (без метода arg),
компилятор сгенерировал это по умолчанию
потому что не было найдено явного super()
как первое утверждение.
- байт-код для инициализации
переменная экземпляра
someint
.
- байт-код для остальных вещей в
тело конструктора.