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 反射机制主要提供了以下功能

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时判断任意一个类所具有的成员变量和方法。

  • 在运行时调用任意一个对象的方法。

简单应用

  1. 通过Class类获取成员变量、成员方法、接口、超类、构造方法等

  2. 运行时复制对象

  3. 用反射机制调用对象的方法

  4. 动态创建和访问数组

  5. 运行时变更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

转自:http://www.jianshu.com/p/d58b96641cbc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值