Java 反射机制
Java 反射机制
什么是反射
Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
在Java中的反射机制,被称为Reflection。(大家看到这个单词,第一个想法应该就是去开发文档中搜一下了。)它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods。
Java 反射机制主要提供了以下功能
-
在运行时判断任意一个对象所属的类。
-
在运行时构造任意一个类的对象。
-
在运行时判断任意一个类所具有的成员变量和方法。
-
在运行时调用任意一个对象的方法。
简单应用
- 通过Class类获取成员变量、成员方法、接口、超类、构造方法等
-
运行时复制对象
-
用反射机制调用对象的方法
-
动态创建和访问数组
-
运行时变更field内容
Java 反射
核心类,位于java.lang.reflect包中
-
Class类:代表一个类。
-
Field 类:代表类的成员变量(成员变量也称为类的属性)。
-
Method类:代表类的方法。
-
Constructor 类:代表类的构造方法。
-
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
核心 API
在 java.lang.Object 类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。
获取类的完整名字
- public String getName() :获得类的完整名字。
获取构造方法
-
Constructor getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数
-
Constructor getConstructors() 返回所有具有public属性的构造函数数组
-
Constructor getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
-
Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)
获取类的成员方法
-
Method getMethod(String name, Class[] parameterTypes) 根据方法名和参数,返回一个具体的具有public属性的方法
-
Method[] getMethods() 返回所有具有public属性的方法数组
-
Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
-
Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性),不包含继承来的方法
获取类的成员变量(成员属性)
-
Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
-
Field[] getFields() 返回具有public属性的成员变量的数组
-
Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)
-
Field[] getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)
获取类、属性、方法的修饰域
类Class、Method、Constructor、Field都有一个public方法int getModifiers()。该方法返回一个int类型的数,表示被修饰对象( Class、 Method、 Constructor、 Field )的修饰类型的组合值。
//打印输出方法的修饰域
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod) + "");
创建类的一个实例
// 利用newInstance()方法,获取构造方法的实例
Object obj = cls.newInstance();
// Class的newInstance方法,仅提供默认无参的实例化方法,类似于无参的构造方法
// Constructor的newInstance方法,提供了带参数的实例化方法,类似于含参的构造方法
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
调用方法
-
public Object invoke(Object obj, Object... args) 调用静态方法时,第一个参数为 null
-
public void setAccessible(boolean flag) 可以改变私有方法的权限
原理
java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class中的类型信息,将这些信息存储到方法区中。这些信息主要包括:
-
这个类型的全限定名
-
这个类型的直接超类的全限定名
-
这个类型是类类型还是接口类型
-
这个类型的访问修饰符
-
任何直接超接口的全限定名的有序列表
-
该类型的常量池
-
字段信息
-
方法信息
-
除了常量以外的所有类变量
-
一个到class类的引用
应用
解析 Json 格式数据,并利用反射创建对应对象
利用反射调用私有方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class LoadMethodEx {
/**
* 在运行时加载指定的类,并调用指定的方法
* @param cName Java的类名
* @param MethodName 方法名
* @param params 方法的参数值
* @return
*/
public Object Load(String cName, String MethodName, Object[] params) {
Object retObject = null;
try {
// 加载指定的类
Class cls = Class.forName(cName); // 获取Class类的对象的方法之二
// 利用newInstance()方法,获取构造方法的实例
// Class的newInstance方法只提供默认无参构造实例
// Constructor的newInstance方法提供带参的构造实例
Constructor ct = cls.getConstructor(null);
Object obj = ct.newInstance(null);
//Object obj = cls.newInstance();
// 根据方法名获取指定方法的参数类型列表
Class paramTypes[] = this.getParamTypes(cls, MethodName);
// 获取指定方法
Method meth = cls.getMethod(MethodName, paramTypes);
meth.setAccessible(true);
// 调用指定的方法并获取返回值为Object类型
retObject = meth.invoke(obj, params);
} catch (Exception e) {
System.err.println(e);
}
return retObject;
}
/**
* 获取参数类型,返回值保存在Class[]中
*/
public Class[] getParamTypes(Class cls, String mName) {
Class[] cs = null;
/*
* Note: 由于我们一般通过反射机制调用的方法,是非public方法
* 所以在此处使用了getDeclaredMethods()方法
*/
Method[] mtd = cls.getDeclaredMethods();
for (int i = 0; i < mtd.length; i++) {
if (!mtd[i].getName().equals(mName)) { // 不是我们需要的参数,则进入下一次循环
continue;
}
cs = mtd[i].getParameterTypes();
}
return cs;
}
}
参考:
http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014582.html
http://lavasoft.blog.51cto.com/62575/43218