Рассмотрим следующий класс Test
, чтобы продемонстрировать поведение внутреннего класса в Java. Основной код находится в методе run
. Остальное — это просто сантехнический код.
public class Test {
private static Test instance = null;
private Test() {
}
private void run() {
new Sub().foo();
}
public static void main(String[] args) {
instance = new Test();
instance.run();
}
class Super {
protected void foo() {
System.out.println("Test$Super.Foo");
}
}
class Sub extends Super {
public void foo() {
System.out.println("Test$Sub.Foo");
super.foo();
}
}
}
Я просто печатаю ниже вывод javap для скрытого конструктора Sub
:
so.Test$Sub(so.Test);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lso/Test;
5: aload_0
6: aload_1
7: invokespecial #2 // Method so/Test$Super."<init>":(Lso/Test;)V
10: return
Обычно компилятор гарантирует, что конструктор подкласса сначала вызовет конструктор суперкласса, прежде чем перейти к инициализации своих собственных полей. Это помогает в правильно сконструированном объекте, но я вижу отклонение от нормативного поведения в случае конструктора, который компилятор генерирует для внутреннего класса. Почему так? Это указано в JLS?
PS: я знаю, что внутренний класс содержит скрытую ссылку на внешний класс, и эта ссылка устанавливается здесь в приведенном выше выводе javap. Но вопрос в том, почему он устанавливается перед вызовом суперконструктора. Что мне не хватает?