Java 反射机制

作者: TerryZhang | 来源:发表于2015-08-23 19:11 被阅读302次

    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类获取成员变量、成员方法、接口、超类、构造方法等
    • 运行时复制对象

    • 用反射机制调用对象的方法

    • 动态创建和访问数组

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

    相关文章

      网友评论

        本文标题:Java 反射机制

        本文链接:https://www.haomeiwen.com/subject/wmexcttx.html