1, 概述
简单来说, JAVA反射机制是指在运行态可直接操作任意类或对象的所有属性和方法的功能。
Java程序可以加载一个运行时才得知名称的class,获悉其完整构造,并生成其对象实体、或对其成员变量赋值、或调用其方法。
这种“看透class”的能力称为反射.
简单使用:
在运行时获取任意对象所属的类
Class<?> clazz = Class.forName(String className);
在运行时构造任意类的对象
Object obj = clazz.newInstance();
在运行时获取任意类所具有的成员变量和方法
field.set(Object obj, Object value);
field.get(Object obj);
在运行时调用任意对象的方法 (最常见的需求,尤其是当该方法是私有方法或者隐藏方法).
method.invoke(Object obj, Object... args);
反射还可以获取类的其他信息,包含modifiers(下面会介绍),以及superclass, 实现的interfaces等。
针对动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。
反射机制在运行时只能调用 methods或改变fields内容,却无法修改程序结构或变量类型。
2, 反射的核心类和方法
2.1 核心类
java.lang.Class: 代表类
java.lang.reflect.Constructor:代表类的构造方法
java.lang.reflect.Field:代表类的属性
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Modifier:代表类、方法、属性的描述修饰符。
其中Modifier取值范围如下: public, protected, private, abstract, static, final,transient, volatile, synchronized, native, strictfp, interface等
Constructor, Field, Method这三个类都继承AccessibleObject,该对象有一个非常重要的方法setAccessible(boolean flag), 借助该方法,
能直接调用非Public的属性与方法。
2.2 核心方法
Class方法如下,
1.获取属性(Field):
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getField(String name)
getDeclaredField(String name):获取类的特定属性
2,获取方法(Method)
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法
getDeclaredMethod(String name, Class[] parameterTypes):获得类的特定方法
3,获取构造方法(Constructor)
getConstructors():获得类的public类型的构造方法。
getDeclaredConstructors():获得类的所有构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法
getDeclaredConstructor(Class[] params);获得类的特定方法
Method核心类
调用方法
invoke(Object receiver, Object... args); 调用类的方法
Class类分析
1, Java所有的类都是继承于Oject类,其内声明了多个应该被所有Java类覆写的方法:
hashCode()、equals()、 clone()、toString()、notify()、wait()、getClass()等,其中getClass返回的便是一个Class类的对 象
。Class类也同样是继承Object类,拥有相应的方法。
2, Java程序在运行时,运行时系统对每一个对象都有一项类型标识,用于记录对象所属的类。
虚拟机使用运行时类型来选择相应方法去执行,保存所有对象类型信息的类便是Class类。
3,Class类没有公共构造方法,Class对象是在加载类时由 Java 虚拟机以及通过调用
ClassLoader的defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
4,虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。
运行程序时,Java虚拟机(JVM)首先检 查是否所要加载的类对应的Class对象是否已经加载。
如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
5,基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和
关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,
所有具有相同元素类型和维数的数组都共享该 Class 对象。一般某个类的Class对象被载入内存,
它就用来创建这个类的所有对象。
2.3反射使用方法
在Android的源码中,我们会发现有很多被”@hide”标记的类,它的作用是使这个类或方法在生成SDK时不可见。
那么应用程序便不可以直接调用。而反射机制可调用@hide标记的类或方法,如入无人之地,畅通无阻。
调用私有类,或者类的私有方法或属性
私有类: 通过getDeclaredConstructor获取constructor,
再调用constructor.setAccessible(true);
私有方法:通过getDeclaredMethod获取method,
再调用method.setAccessible(true);
私有属性:通过getDeclaredField获取field,再调用field.setAccessible(true);
对于正常方式来调用方法,往往只需要一行到两行代码,即可完成相应工作。
而反射则显得比较繁琐,之所以繁琐仍会才用反射方式,是因为反射能干很多正常实例化对象的方式所无法做到的事。
比如操作那些private的类、方法、属性,以及@hide标记过的类、方法、属性。
3,反射利弊
反射最大的好处是可以操作非API接口,其他就不多说了。
反射缺点:
1,因为可以随意对类进行操作,所以第一个问题就是安全问题。
2, 因为是动态执行的,效率自然没有预编译时引用现有的库效率高。
3, 因为反射是动态的,所以需要处理很多异常,不然Dalvik崩溃出Force Close的概率会大很多。
所以,不到非不得已,最好不要使用反射。