定義一個包含非靜態(tài)內部類的類
public class Outer {
//內部類
public class Inner{
private String name = "默認值";
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;
}
}
}
利用反射的方法獲取內部類的實例
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)建內部的實例時痘系,為什么會傳入了Outer類的實例,我們明明在內部類中饿自,定義了下面兩個構造器疤洹?
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 默認值
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 默認值
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)內部類Inner并沒有無參的構造器复唤,它的構造器需要一個Outer參數(shù)。
為什么會這樣烛卧?
系統(tǒng)在編譯階段總會為非靜態(tài)內部類的構造器增加一個參數(shù)佛纫,非靜態(tài)內部類的構造器的第一個參數(shù)總是外部類。因此調用非靜態(tài)內部類的構造器時必須傳入一個外部類對象作為參數(shù)总放,否則程序將會引發(fā)運行時異常呈宇。
非靜態(tài)內部類的規(guī)則
非靜態(tài)內部類必須寄生在外部類的實例中,沒有外部類的對象局雄,就不可能產生非靜態(tài)內部類的對象甥啄。因此非靜態(tài)內部類不可能有無參的的構造器---即使系統(tǒng)為非靜態(tài)內部類提供一個默認的構造器,這個默認的的構造器也需要一個外部類的形參哎榴。
如果要繼承一個非靜態(tài)內部類該怎么寫哩
public class Test extends Outer.Inner{
/**
* 為什么要這么寫型豁?
* 因為Inner類沒有無參構造器
* 使用 new Outer()作為主調----即以一個Out對象作為主調,
* 其實這個主調會作為參數(shù)傳入super()尚蝌,也就是傳給Inner類的帶一個Out參數(shù)的構造器迎变。
*/
public Test(){
new Outer().super();
}
}