定義一個包含非靜態(tài)內(nèi)部類的類
public class Outer {
//內(nèi)部類
public class Inner{
private String name = "默認(rèn)值";
public Inner(){
}
public Inner(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString(){
return "Inner 對象:"+this.name;
}
}
}
利用反射的方法獲取內(nèi)部類的實例
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(new Outer().new Inner());
//使用反射的方法創(chuàng)建
Class cls = Outer.Inner.class;
Constructor constructor1 = cls.getDeclaredConstructor(Outer.class);
Constructor constructor2 = cls.getDeclaredConstructor(Outer.class, String.class);
Outer.Inner in1 = (Outer.Inner) constructor1.newInstance(new Outer());
Outer.Inner in2 = (Outer.Inner) constructor2.newInstance(new Outer(), "測試");
System.out.println(in1);
System.out.println(in2);
}
}
在用反射創(chuàng)建內(nèi)部的實例時,為什么會傳入了Outer類的實例,我們明明在內(nèi)部類中,定義了下面兩個構(gòu)造器???
public Inner(){
}
public Inner(String name){
this.name = name;
}
使用javap工具分析Inner類
javap -c Outer$Inner.class 命令得到如下文件
Compiled from "Outer.java"
public class com.nanc.Outer$Inner {
final com.nanc.Outer this$0;
public com.nanc.Outer$Inner(com.nanc.Outer);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lcom/nanc/Outer;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: aload_0
10: ldc #3 // String 默認(rèn)值
12: putfield #4 // Field name:Ljava/lang/String;
15: return
public com.nanc.Outer$Inner(com.nanc.Outer, java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lcom/nanc/Outer;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: aload_0
10: ldc #3 // String 默認(rèn)值
12: putfield #4 // Field name:Ljava/lang/String;
15: aload_0
16: aload_2
17: putfield #4 // Field name:Ljava/lang/String;
20: return
public java.lang.String getName();
Code:
0: aload_0
1: getfield #4 // Field name:Ljava/lang/String;
4: areturn
public void setName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #4 // Field name:Ljava/lang/String;
5: return
public java.lang.String toString();
Code:
0: new #5 // class java/lang/StringBuilder
3: dup
4: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
7: ldc #7 // String Inner 對象:
9: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
12: aload_0
13: getfield #4 // Field name:Ljava/lang/String;
16: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: areturn
}
可以明顯看到,非靜態(tài)內(nèi)部類Inner并沒有無參的構(gòu)造器,它的構(gòu)造器需要一個Outer參數(shù)。
為什么會這樣?
系統(tǒng)在編譯階段總會為非靜態(tài)內(nèi)部類的構(gòu)造器增加一個參數(shù),非靜態(tài)內(nèi)部類的構(gòu)造器的第一個參數(shù)總是外部類。因此調(diào)用非靜態(tài)內(nèi)部類的構(gòu)造器時必須傳入一個外部類對象作為參數(shù),否則程序?qū)l(fā)運行時異常。
非靜態(tài)內(nèi)部類的規(guī)則
非靜態(tài)內(nèi)部類必須寄生在外部類的實例中,沒有外部類的對象,就不可能產(chǎn)生非靜態(tài)內(nèi)部類的對象。因此非靜態(tài)內(nèi)部類不可能有無參的的構(gòu)造器---即使系統(tǒng)為非靜態(tài)內(nèi)部類提供一個默認(rèn)的構(gòu)造器,這個默認(rèn)的的構(gòu)造器也需要一個外部類的形參。
如果要繼承一個非靜態(tài)內(nèi)部類該怎么寫哩
public class Test extends Outer.Inner{
/**
* 為什么要這么寫?
* 因為Inner類沒有無參構(gòu)造器
* 使用 new Outer()作為主調(diào)----即以一個Out對象作為主調(diào),
* 其實這個主調(diào)會作為參數(shù)傳入super(),也就是傳給Inner類的帶一個Out參數(shù)的構(gòu)造器。
*/
public Test(){
new Outer().super();
}
}