http://mp.weixin.qq.com/s?__biz=MzI3NDA3Njg3Mw==&mid=507802146&idx=1&sn=5fc889e27f480a7e4eccb7d011d4c1d3&scene=23&srcid=0419T28hvOOsyuVMnfQDZhiZ#rd
反射调用是什么?从有限的文档里,我找到了一篇1998的文章《Use Java Reflection》,by Glen McClusKey。这边提到的一个用途是用来动态检测组件(类)的功能。有兴趣的可以查看这边文章:http://www.oracle.com/technetwork/articles/java/javareflection-1536171.html
抛开上述文章不谈,因为这边文章写得也很早,略显过时。我们根据当下的使用场景来谈谈我对反射调用的理解:
01 理解概念我们需要区分普通调用和反射调用的区别。普通调用是客观存在的,一定可以调得到;反射调用这是主观猜测,不一定可以调得到。比如,我们定义一个女性类,开放出来的方法为isAdulty() 和isBeauty()
package com.reflect.test;
class Woman {
private int age; // 年龄
private boolean beauty; // 是否漂亮
public boolean isAdulty() {
return age >= 18;
}
public boolean isBeauty() {
return beauty;
}
protected int getAge() {
return age;
}
}
普通调用,仅可以调用:
Woman woman = new Woman();
woman.isBeauty();
woman.isAdulty();
反射调用,比如我们调用一个不公开的方法,比如getAge这个方法:
public int getAgeByReflect() throws Exception {
Class<?> clz = Woman.class;
Object obj = clz.newInstance();
Method method = clz.getDeclaredMethod("getAge", null);
method.setAccessible(true);
return (Integer)method.invoke(obj);
}
我们就可以获得这位女性的年龄这一私密信息。
但是我们尝试getMoney呢?答案当然是获取不到的,但我们程序是可以运行起来的。
如上图所示:
1)绿色流程则是从类名->对象的转换;
2)红色这是该类的成员,从左到右依次:子类,注释,方法,变量
3)黄色这是判断第2步的成员是否是静态变量
4)蓝色则是调用,分为static直接调用,非static则必须传入a这个对象来访问。
03Class
从上面的流程图,可以看出Class 是一切反射的源泉,没有这个,都是空谈,所以,我们重点讲一下如何获取Class对象。
1)通过类名获取
Class clz = Class.forName("com.test.A");
2)通过对象获取
比如我们已经创建了一个对象
A a = new A();
Class clz = a.getClass();
3)通过静态获取
Class clz = A.class;
注意:同时也支持int,boolean,数组之类的,则可以通过如下
Class clz = int.class;
Class clz = int[].class;
04Method获取了Class 或者对象,接下来我们来看看如何调用方法
1)static方法
public int getAgeByReflect() throws Exception {
Class<?> clz = Woman.class;
//Object obj = clz.newInstance();
Method method = clz.getDeclaredMethod("getAge", null);
method.setAccessible(true);
return (Integer)method.invoke(null);
}
2)非static方法
public int getAgeByReflect() throws Exception {
Class<?> clz = Woman.class;
Object obj = clz.newInstance();
Method method = clz.getDeclaredMethod("getAge", null);
method.setAccessible(true);
return (Integer)method.invoke(obj);
}
同样方式,可以访问到变量
1)static变量
public int getAgeFieldByReflect() throws Exception {
Class<?> clz = Woman.class;
//Object obj = clz.newInstance();
Field field = clz.getDeclaredField("age");
field.setAccessible(true);
return (Integer)field.get(null);
}
2)非static变量
public int getAgeFieldByReflect() throws Exception {
Class<?> clz = Woman.class;
Object obj = clz.newInstance();
Field field = clz.getDeclaredField("age");
field.setAccessible(true);
return (Integer)field.get(obj);
}
限定符,用来修饰用,public、private、static、final等
比如方法,可以通过调用
int modifiers = method.getModifiers();
然后,调用Modifier.isPublic(modifiers); 判断是不是public,true代表是共有方法。同理,对于其他成员也可以使用!
1)Android未公开API
众所周知,Android系统有一些隐藏的API是不对外开放的,仅限系统APP调用。那么,就可以使用反射调用的机制来访问到这些API。
2)动态插件调用
现在很多APP为了瘦身,将功能按模块划分,部分模块独立做成插件放至服务器,再动态下发至客户端。APP调用插件的方式便是采用反射调用的方法。目前市面上很多大公司的APP都实现了插件化功能,比如淘宝、手机管家、GO桌面等,这些APP功能复杂,但安装包特别小!