使用反射的方法,创建一个非静态内部类的实例
2018-07-04 本文已影响0人
缓慢移动的蜗牛
定义一个包含非静态内部类的类
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());
//使用反射的方法创建
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);
}
}
在用反射创建内部的实例时,为什么会传入了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
}
可以明显看到,非静态内部类Inner并没有无参的构造器,它的构造器需要一个Outer参数。
为什么会这样?
系统在编译阶段总会为非静态内部类的构造器增加一个参数,非静态内部类的构造器的第一个参数总是外部类。因此调用非静态内部类的构造器时必须传入一个外部类对象作为参数,否则程序将会引发运行时异常。
非静态内部类的规则
非静态内部类必须寄生在外部类的实例中,没有外部类的对象,就不可能产生非静态内部类的对象。因此非静态内部类不可能有无参的的构造器---即使系统为非静态内部类提供一个默认的构造器,这个默认的的构造器也需要一个外部类的形参。
如果要继承一个非静态内部类该怎么写哩
public class Test extends Outer.Inner{
/**
* 为什么要这么写?
* 因为Inner类没有无参构造器
* 使用 new Outer()作为主调----即以一个Out对象作为主调,
* 其实这个主调会作为参数传入super(),也就是传给Inner类的带一个Out参数的构造器。
*/
public Test(){
new Outer().super();
}
}