zoukankan      html  css  js  c++  java
  • (转)JAVA-反射机制的使用

    Java反射机制的实现原理


        反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。下面具体介绍一下java的反射机制。这里你将颠覆原来对java的理解。 

        Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组成部分。

      Class:程序运行时,java运行时系统会对所有的对象进行运行时类型的处理。这项信息记录了每个对象所属的类,虚拟机通常使用运行时类型信息选择正确的方法来执行(摘自:白皮书)。但是这些信息我们怎么得到啊,就要借助于class类对象了啊。在Object类中定义了getClass()方法。我们可以通过这个方法获得指定对象的类对象。

    Java反射机制主要提供了以下功能:

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

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

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

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

      Reflection是Java被视为动态(或准动态)语言的一个关键性质。

      这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息。

      包括其modifiers(诸如public、static等)、 superclass(例如Object)、实现了的 interfaces (例如Serializable)、也包括其fields和methods的所有信息,并可于运行时改变fields内容或调用methods。

    然后我们通过分析这个对象就可以得到我们要的信息了。

    比如:ArrayList arrayList;

    Class clazz = arrayList.getClass();

    然后我来处理这个对象clazz。

    当然了Class类具有很多的方法,这里重点将和Constructor,Field,Method类有关系的方法。

    Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是个人认为要想对java有个更加深入的了解还是应该掌握的。

    1.检测类:

    reflection的工作机制

    考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

    import java.lang.reflect.Method;

    public class DumpMethods {

    public static void main(String args[]) {

    try {

    Class c = Class.forName(args[0]);

    Method m[] = c.getDeclaredMethods();

    for (int i = 0; i < m.length; i++)

    System.out.println(m[i].toString());

    } catch (Throwable e) {

    System.err.println(e);

    }

    }

    }



    按如下语句执行:

    java DumpMethods java.util.ArrayList

    这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

    Java类反射中的主要方法

        对于以下三类组件中的任何一类来说 -- 构造函数、字段和方法 -- java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。以下是用于查找构造函数的一组反射调用:

        Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,

        Constructor[] getConstructors() -- 获得类的所有公共构造函数

        Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)

        Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)

    获得字段信息的Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名:

        Field getField(String name) -- 获得命名的公共字段

        Field[] getFields() -- 获得类的所有公共字段

        Field getDeclaredField(String name) -- 获得类声明的命名的字段

        Field[] getDeclaredFields() -- 获得类声明的所有字段

    用于获得方法信息函数:

        Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法

        Method[] getMethods() -- 获得类的所有公共方法

        Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法

        Method[] getDeclaredMethods() -- 获得类声明的所有方法

    使用 Reflection:

        用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。

    下面就是获得一个 Class 对象的方法之一:

        Class c = Class.forName("java.lang.String");

        这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:

        Class c = int.class; 或者  Class c = Integer.TYPE;

    它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Intege ) 中预先定义好的 TYPE 字段。

    第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。

    一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:

    Class c = Class.forName("java.lang.String");

    Method m[] = c.getDeclaredMethods();

    System.out.println(m[0].toString());

    它将以文本方式打印出 String 中定义的第一个方法的原型。

    处理对象:

        a.创建一个Class对象
        b.通过getField 创建一个Field对象
        c.调用Field.getXXX(Object)方法(XXX是Int,Float等,如果是对象就省略;Object是指实例).

    例如:

    import java.lang.reflect.*;

    import java.awt.*;

    public class SampleGet {

    public static void main(String[] args) {

    Rectangle r = new Rectangle(100, 325);

    printHeight(r);

    }

    static void printHeight(Rectangle r) {

    Field heightField;

    Integer heightValue;

    Class c = r.getClass();

    try {

    heightField = c.getField("height");

    heightValue = (Integer) heightField.get(r);

    System.out.println("Height: " + heightValue.toString());

    } catch (NoSuchFieldException e) {

    System.out.println(e);

    } catch (SecurityException e) {

    System.out.println(e);

    } catch (IllegalAccessException e) {

    System.out.println(e);

    }

    }

    }

    生成对象

     1.先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

      Class<?> classType = String.class;
      Object obj = classType.newInstance();

        2.先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成(其中Customer是一个自定义的类,有一个无参数的构造方法,也有带参数的构造方法):

        Class<?> classType = Customer.class;

        // 获得Constructor对象,此处获取第一个无参数的构造方法的

        Constructor cons = classType.getConstructor(new Class[] {});

        // 通过构造方法来生成一个对象

        Object obj = cons.newInstance(new Object[] {});

    3.若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:

    (Customer为一个自定义的类,有无参数的构造方法,也有一个带参数的构造方法,传入字符串和整型)

        Class<?> classType = Customer.class;
        Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});
        Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});

    可以看出调用构造方法生成对象的方法和调用一般方法的类似,不同的是从Class对象获取Constructor对象时不需要指定名字,而获取Method对象时需要指定名字

  • 相关阅读:
    洛谷 P4071 [SDOI2016]排列计数
    问题 G: 【一本通提高同余问题】计算器
    问题 A: 【一本通提高组合数学】Bullcow 牡牛和牝牛
    浅谈卢卡斯定理(非扩展)
    2019西安联训B层 Day 6练习题 问题 C: 扩展欧几里得
    react使用lazy()和Suspense实现根据路由进行代码分割
    react-loadable 使用高阶组件动态import组件,实现代码分割(code-splitting)
    react angular vue流行度对比
    react 服务端渲染(ssr) 框架 Next.js
    超级字符串内class正则匹配替换 可以用于css modules
  • 原文地址:https://www.cnblogs.com/gaoxiangde/p/4190472.html
Copyright © 2011-2022 走看看