问:如下代码段,已获取外部类实例情况下如何反射实例化内部类及调用内部类方法?
class OuterClass {
public void func(){
System.out.println("Outer class.");
}
class InnerClass {
private String mName;
public InnerClass(String name) {
mName = name;
}
void getName(){
System.out.println("name is:"+mName);
}
}
}
答:本题贵在考察反射内部类的注意事项,实质就是在考察对于内部类的理解,内部类不了解的可以查看本号历史推送中内部类面试专题。下面直接给出答案完整代码,如下。
class OuterClass {
public void func() {
System.out.println("Outer class.");
}
class InnerClass {
private String mName;
public InnerClass(String name) {
mName = name;
}
void getName() {
System.out.println("name is:"+mName);
}
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Class outerClass = Class.forName("OuterClass");
//通过外部类的方法名获取外部类的方法
Method method = outerClass.getDeclaredMethod("func");
//调用外部类实例的func方法,invoke第一参数为外部类实例
method.invoke(outerClass.newInstance());
//内部类反射名字需要使用$分隔,编译后生成的规则
Class innerClass = Class.forName("OuterClass$InnerClass");
//通过内部类的方法名获取内部类的方法
Method method2 = innerClass.getDeclaredMethod("getName");
//特别注意!!!!内部类newInstance的第一个参数必须是外部类实例的引用
method2.invoke(innerClass.getDeclaredConstructors()[0].newInstance(outerClass.newInstance(),"yan"));
}
}
即便上面 InnerClass 的修饰符是 private,上面的代码依旧可以成功反射,只是不能直接通过 outClass.new InnerClass(“yan”); 的方式去实例化内部类。
同理当上面 InnerClass 的修饰符如果是 static,即内部类是静态内部类时上面的代码就不能用了,需要将答案的最后一行代码改成 method2.invoke(innerClass.getDeclaredConstructors()[0].newInstance(“yan”)); 才行,因为静态内部类没有持有外部类的任何引用,所以不用传递外部类实例对象的引用。
问:如何反射如下类的匿名内部成员类?
class OuterClass {
public Runnable runnable = new Runnable() {
public void run() {
System.out.println("runnable.");
}
};
}
答:其实这种场景你就不要把它想成匿名内部类了,直接当作外部类的成员变量去反射即可,如下。
class OuterClass {
public Runnable runnable = new Runnable() {
public void run() {
System.out.println("runnable.");
}
};
}
public class Demo {
public static void main(String[] args) throws Exception {
Class outerClass = Class.forName("OuterClass");
Runnable runnable = (Runnable) (outerClass.getField("runnable").get(outerClass.newInstance()));
runnable.run();
}
}
所以说,想要灵活运用反射,用好反射就必须先熟练掌握 Java 各种核心基础知识,譬如变长参数、内部类实质原理等等,不然在写反射代码时会觉得很懵逼。