问:如下代码段,已获取外部类实例情况下,如何反射实例化内部类及调用内部类方法?
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();
}
}