上篇博客我们讲了 Class 类,也是为本篇做铺垫的。下面进入正文
答:在程序运行状态时,对于任意一个类,都能够知道这个类的所有构造函数,方法和属性;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态编译的概念, 静态编译:在编译时确定类型,绑定对象,即通过。 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
优点:就是可以实现动态创建对象和编译,体现出很大的灵活性。缺点:对性能有影响。反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。获得构造函数的方法
//根据指定参数获得public构造器 Constructor getConstructor(Class[] params); //获得public的所有构造器 Constructor[] getConstructors(); //根据指定参数获得public和非public的构造器 Constructor getDeclaredConstructor(Class[] params); //获得public的所有构造器 Constructor[] getDeclaredConstructors();看这些方法如何使用,先来个Student类供我们反射使用
public class Student { private static String TAG = Student.class.getSimpleName(); public int age; private String name; public Student() { age = 20; name = "小明"; } public Student(int age, String name) { Log.e(TAG, "Student: " + "age " + age + " name " + name); } public void StudentA() { Log.e(TAG, "StudentA: "); } public void StudentA(int age) { Log.e(TAG, "StudentA: " + "age " + age); } public void StudentA(int age, String name) { Log.e(TAG, "StudentA: " + "age " + age + " name " + name); } }控制台打印日志如下:
03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student() 03-08 19:02:21.051 17440-17440/zhangqilu.com.plugin I/System.out: zhangqilu.com.plugin.Student(int,java.lang.String)打印出2个构造函数,一个是没有参数构造函数Student(), 另一个是有2个参数(int和String类型)的构造函数 Student(int,java.lang.String)
Class[] params 构造函数的参数类型 的 类类型 使用如下
//通过 包名+类名 获取 Student类类型 Class stuentClass = Class.forName("zhangqilu.com.plugin.Student"); //通过 Student类类型获取 构造函数 int.class, String.class 构造函数的参数类型 的 类类型 Constructor constructor = stuentClass.getConstructor(int.class, String.class); //创建Student类实例 构造函数参数 age 100 name dog Object object = constructor.newInstance(100, "dog");控制台打印日志如下:
03-08 19:54:13.029 25292-25292/? E/Student: Student: age 100 name dog构造函数的反射主要就2种情况,1是获取所有构造函数, 2是根据指定参数获取构造函数。下面我们来看看方法的反射。
获得类方法的方法 Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法
//获得所有的public方法包括父类继承而来的 Method[] getMethods(); //根据方法名和参数类型,获得public和非public的方法 Method getDeclaredMethod(String name, Class[] params); Method[] getDeclaredMethods()//获得所以的public和非public方法 ;控制台打印日志如下
03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA() 03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int) 03-09 10:41:45.392 10495-10495/? I/System.out: void StudentA(int,java.lang.String) 03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Object access$super(zhangqilu.com.plugin.Student,java.lang.String,[Ljava.lang.Object;) 03-09 10:41:45.392 10495-10495/? I/System.out: boolean equals(java.lang.Object) 03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.Class getClass() 03-09 10:41:45.392 10495-10495/? I/System.out: int hashCode() 03-09 10:41:45.392 10495-10495/? I/System.out: void notify() 03-09 10:41:45.392 10495-10495/? I/System.out: void notifyAll() 03-09 10:41:45.392 10495-10495/? I/System.out: java.lang.String toString() 03-09 10:41:45.392 10495-10495/? I/System.out: void wait() 03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long) 03-09 10:41:45.392 10495-10495/? I/System.out: void wait(long,int)我们还要看一个反射的重要方法
public Object invoke(Object obj,Object... args)参数理解: obj 反射方法的对象(调用谁的方法用谁的对象) 如果方法为 静态的 obj 可以为null args 用于方法调用的参数
体使用如下:
Class studentClass = Class.forName("zhangqilu.com.plugin.Student");//通过 包名+类名 获取 Student 类类型; Object object = studentClass.newInstance();//获取Student 实例; Method method = studentClass.getMethod("StudentA", int.class, String.class);//根据方法名和参数类型获取方法实例; method.invoke(object, 20, "zhangqilu");//反射执行方法控制台打印日志如下
03-09 16:02:55.082 2372-2372/zhangqilu.com.plugin E/Student: StudentA: age 20 name zhangqilu获得类中属性的方法
//根据变量名得到相应的public变量 Field getField(String name) //获得类中所以public的方法 Field[] getFields() //根据方法名获得public和非public变量 Field getDeclaredField(String name) //获得类中所有的public和非public方法 Field[] getDeclaredFields()属性反射和构造函数和方法反射类似,我们只说
Field getDeclaredField(String name)使用。
Class stuentClass = Class.forName("zhangqilu.com.plugin.Student"); Object object = stuentClass.newInstance(); Field field = stuentClass.getField("age"); int age = (int) field.get(object); Log.e(TAG, "reflectionField: age " + age); Field field1 = stuentClass.getDeclaredField("name"); /* Java代码中,常常将一个类的成员变量置为private 在类的外面获取此类的私有成员变量的value时,需要注意: 将field.setAccessible(true); */ field1.setAccessible(true); String name = (String) field1.get(object); Log.e(TAG, "reflectionField: name " + name);控制台打印日志如下。
03-09 16:19:54.337 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: age 20 03-09 16:19:54.338 14194-14194/zhangqilu.com.plugin E/MainActivity: reflectionField: name 小明反射就说到这里,下一篇我们讲代理(静态代理和动态代理)。