反射机制
1、反射的作用
一般情况下,我们想得到一个类的实例只需要直接创建它就好了,如现在有一个类文件Person.class, 创建对象代码如下
Person p = new Person();
现在我们假设一种场景,我们在配置文件中记录下一个类名及它的一个方法名,然后我们将该配置文件读取出来,能否通过里面的字串内容来得到对应的实例并执行方法呢?答案是肯定的,这正是反射存在的原因,它一般出现在框架的搭建。配置文件可以这样写
com.xxx.cn.Person getName
上面第一个字串是类的全名,第二个为方法名。
2、如何通过反射来执行字串中的方法名呢
介绍反射的文章很多,在最开始的学习中,始终没有真正理会,总是在看了忘忘了看的循环中,原因就在于只知其然不知其所以然,在这我按自己的理解来分解介绍。
现在回到问题原点,怎么将一个表示类名的字串转化成实例并执行它的方法, 我将整个过程分为三部分
1)根据类名得到类
2)反射得到类的构造方法并实例化
3)反射方法并调用
这样一分,整个反射过程就变得很简单了,不再因为各种各样的反射API而不知所措了。
3、反射API
以ExamNameBean为例来一一说明
public class ExamNameBean implements Serializable { private static final long serialVersionUID = 1557158345411694553L; public ExamNameBean(int i, String s){
Log.d(TAG, "ExamNameBean: ");
} private String examName; private long uploadTime; private boolean correct; public String getExamName() { return examName; } public void setExamName(String examName) { this.examName = examName; } public long getUploadTime() { return uploadTime; } public void setUploadTime(long uploadTime) { this.uploadTime = uploadTime; } private boolean isCorrect() { return correct; } private void setCorrect(boolean correct) { this.correct = correct; } }
获取类的方法有三种
Class<?> class1 = null; Class<?> class2 = null; Class<?> class3 = null; // 三种方式获取 class1 = Class.forName("com.xxx.packetname.ExamNameBean"); class2 = new ExamNameBean().getClass(); class3 = ExamNameBean.class;
接着反射类的构造方法并实例化
Class c = Class.forName("com.xxx.ExamNameBean"); //取公共的无参构造函数 Constructor construct = c.getConstructor(null); //取有参的构造函数 Constructor c2 = c.getConstructor(int.class, String.class); //实例化对像 ExamNameBean exam = (ExamNameBean) construct.newInstance(); ExamNameBean exam2 = (ExamNameBean) c2.newInstance(1,"name");
在得到实例化后的对象,这个时候只要再把方法反射出来就可以调用了
Method m = c.getMethod("getExamName", null); m.invoke(exam, null); //getExamName()调用,需要指定类实例,表示是调用谁的方法
以上反射的方法及构造函数,都是公共属性的,那怎么访问私有方法呢,正常情况下,我们是没法调用对象的私有方法的,但是在反射时,却可以通过暴力反射去访问类的私有成员,包括私有构造方法,私有变量,私有方法等
Method privateM = c.getDeclaredMethod("test", null); privateM.setAccessible(true);//暴力反射 privateM.invoke(exam,null);
总结
反射时,凡涉及到私有属性的成员反射时,其API名字都具有getDeclaredXXX()特点,并需要setAccessible(true)将其暴露出来,如果是公共成员的反射API名都不带Declared字样。
获取构造方法 getConstructors getDeclaredConstructors · 获取所有成员 getFields getDeclaredFields · 获取单个成员 getField getDeclaredField · 修改成员的值 set(Object obj,Object value) :将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 · 获取所有方法 getMethods getDeclaredMethods · 获取单个方法 getMethod getDeclaredMethod · 暴力访问 method.setAccessible(true);