在使用反射生成泛型的具体对象实例时发现没有达到自己的预期目的,所以研究了一下constructor.newInstance()
方法。我的问题是在创建具体类型传给反射使用时,会出现找不到相应构造函数的情况。
利用反编译查看发现外部类和内部类调用构造函数时传入的参数是不一样的,以下是讲解的例子。
首先声明三个类:非静态内部类,静态内部类,布局内部类。
public class InnerClass {
// 非静态内部类
class InnerA {
private String name;
public InnerA(String name) {this.name = name;}
public InnerA() {}
}
// 静态内部类
static class InnerB {
private String name;
public InnerB(String name) {this.name = name;}
public InnerB() {}
}
private void show() {
// 局部内部类
class InnerC {
private String name;
public InnerC(String name) {this.name = name;}
public InnerC() {}
}
}
}
反编译后生成4个class
文件:
- InnerClass.class
- InnerClass$InnerA.class
- InnerClass$InnerB.class
- InnerClass$1InnerC.class
利用javap -c
命令查看三个内部类发现其构造方法如下:
由上可以发现,当这个实例的类是静态内部类时第一个参数不需要传入外部类,如果是非静态内部类和局部内部类第一个参数则需要传入外部类。
在弄明白这个情况后,当我们调用getDeclaredConstructor()
和newInstance()
方法时就能根据这个实例的类所在的位置而针对第一个参数做相应的调整了。
其调整如下:
- 如果实例的类是外部类和静态内部类,第一个参数不用考虑
- 如果实例的类是非静态内部类和局部内部类,第一个参数需要传入这个类所在的外部类。
如何判断一个类是外部类还是内部类或者是局部内部类呢?可以利用class
提供的方法,也可以配合Modifier
这个类使用。
利用以上方法可以根据不同的情况调用不同方法:
// 非静态内部类和局部内部类
if (z.isLocalClass() || !Modifier.isStatic(z.getModifiers()) && z.isMemberClass()) {
try {
constructor = z.getDeclaredConstructor(getClass(), String.class);
object = constructor.newInstance(this, s);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else { // 外部类和静态内部类
try {
constructor = z.getDeclaredConstructor(String.class);
object = constructor.newInstance(s);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}