Ответ 1
Прежде всего, спасибо за этот интересный вопрос. Я был настолько заинтригован, что не мог удержаться от взгляда на бат-код. Это байт-код TestNested
:
Compiled from "TestNested.java"
public class a.TestNested {
public a.TestNested();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc_w #2 // class a/TestNested$A
3: astore_1
4: aload_1
5: invokevirtual #3 // Method java/lang/Class.getDeclaredConstructors:()[Ljava/lang/reflect/Constructor;
8: astore_2
9: aload_2
10: arraylength
11: istore_3
12: iconst_0
13: istore 4
15: iload 4
17: iload_3
18: if_icmpge 41
21: aload_2
22: iload 4
24: aaload
25: astore 5
27: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload 5
32: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
35: iinc 4, 1
38: goto 15
41: new #2 // class a/TestNested$A
44: dup
45: new #6 // class a/TestNested
48: dup
49: invokespecial #7 // Method "<init>":()V
52: dup
53: invokevirtual #8 // Method java/lang/Object.getClass:()Ljava/lang/Class;
56: pop
57: bipush 123
59: aconst_null
60: invokespecial #9 // Method a/TestNested$A."<init>":(La/TestNested;ILa/TestNested$1;)V
63: astore_2
64: return
}
Как вы можете видеть, конструктор a.TestNested$A(a.TestNested,int,a.TestNested$1)
вызывается из вашего метода main
. Кроме того, null
передается как значение параметра a.TestNested$1
.
Итак, посмотрим на таинственный анонимный класс a.TestNested$1
:
Compiled from "TestNested.java"
class a.TestNested$1 {
}
Странно - я бы ожидал, что этот класс действительно что-то сделает. Чтобы понять это, взгляните на конструкторы в a.TestNested$A
: class a.TestNested $A { final a.TestNested this $0;
a.TestNested$A(a.TestNested);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field this$0:La/TestNested;
5: aload_0
6: invokespecial #3 // Method java/lang/Object."<init>":()V
9: return
private a.TestNested$A(a.TestNested, int);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field this$0:La/TestNested;
5: aload_0
6: invokespecial #3 // Method java/lang/Object."<init>":()V
9: return
a.TestNested$A(a.TestNested, int, a.TestNested$1);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #1 // Method "<init>":(La/TestNested;I)V
6: return
}
Посмотрев на конструктор, видимый в пакете a.TestNested$A(a.TestNested, int, a.TestNested$1)
, мы увидим, что третий аргумент игнорируется.
Теперь мы можем объяснить конструктор и анонимный внутренний класс. Дополнительный конструктор необходим, чтобы обойти ограничение видимости для частного конструктора. Этот дополнительный конструктор просто делегирует частный конструктор. Тем не менее, он не может иметь такую же подпись, что и частный конструктор. Из-за этого добавляется анонимный внутренний класс, чтобы обеспечить уникальную подпись, не сталкиваясь с другими возможными перегруженными конструкторами, такими как конструктор с сигнатурой (int,int)
или (int,Object)
. Поскольку этот анонимный внутренний класс необходим только для создания уникальной подписи, его не нужно создавать и не нужно иметь контент.