• 反射基础知识第二篇


    上一篇中讲了如何获取指定类的Class对象,及用Class对象获取该类的构造器、方法、成员变量,本篇主要探讨如何利用这些构造器、方法、成员变量等。

    1.构造器,newInstance(Object ... initargs)方法

    显而易见,利用构造器的目的就是产生一个对应类的实例:

    public static void main(String[] args) {
        Class clazz = A.class;
        Constructor con = null;
        A a = null;
        try {
            con = clazz.getDeclaredConstructor(String.class, int.class);
            // con.setAccessible(true);
            a = (A) con.newInstance("张三", 19);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(a);
    }

         如上,在获取到Constructor对象con之后,可以调用其newInstance(Object ... initargs)方法获取到对应类的对象。值得注意的是,如果构造器A(String name, int age)是private的话,那么如果调用的不是getDeclaredConstructor()而是getConstructor()的话,则会报NoSuchMethodException没有此方法异常;调用getConstructor()得到Constructor对象,这个对象对应一个私有化的构造器,这时候如果直接调用newInstance(Object ... initargs)方法的话,会报IllegalAccessException非法访问权限异常的。解决办法是在调用newInstance(Object ... initargs)方法之前先执行setAccessible(true)。setAccessible(boolean flag)方法是Constructor类、Method类、Field类的公共父类AccessibleObject的方法,也就是说如果构造器、方法的访问权限是private时,要想通过反射调用这个方法,需要在调用前执行setAccessible(true),这样就不会报非法访问权限异常了。

         但是,通常我们创建对应类对象的时候不会用Class对象获取完Constructor对象后再获取对应类实例,而是直接利用Class对象的newInstance()方法,通过这种方式生成对应类实例,其实是利用对应类的默认构造器,即无参构造器,所以对应类要有无参构造器(显示声明无参构造器或者根本就显示声明任何构造器),而且必须是public的,因为Class对象没有setAccessible()方法。

    2.方法,public Object invoke(Object obj, Object... args):

    invoke方法的调用者是一个Method对象,第一个参数是一个对应类的实例,后面参数是方法参数列表。可以看出,用invoke方法调用对应类某个方法的时候,就已经获得对应类的实例了,那为什么还要用invoke方法,而不是直接用对象调用呢?这是因为私有化的方法不能直接通过对象打点调用而只能通过invoke的方式调用:

    public static void main(String[] args) {
        Class clazz = A.class;
        A a = null;
        Method method = null;
        try {
            method = clazz.getDeclaredMethod("say", String.class);
            a = (A) clazz.newInstance();
            method.setAccessible(true);
            method.invoke(a, "zhoujielun");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    如上,Method对象在调用invoke方法之前先执行setAccessible(true)就可以执行对应类的私有化方法了。本例中创建对应类实例的方法就是直接Class对象.newInstance(),而没有通过产生构造器对象,然后利用构造器对象再获取对应类实例的方法。

    3.成员变量,public Object get(Object obj);public void set(Object obj, Object value)

    get方法的参数是一个对应类的实例;

    set方法的第一个参数是一个对应类的实例,第二个参数是要给这个实例的某个成员变量赋的值。

    一个Field对象其实就绑定一个成员变量,在生成Field对象时就绑定了,如Field field=clazz.getDeclaredField("name");,此时field就绑定了name成员变量。

    public static void main(String[] args) {
        Class clazz = A.class;
        A a = null;
        Constructor con = null;
        Field field = null;
        try {
            con = clazz.getDeclaredConstructor(String.class, int.class);
            a = (A) con.newInstance("张三", 19);
            field = clazz.getDeclaredField("name");
    
            String name = (String) field.get(a);
            System.out.println(name);
    
            field = clazz.getDeclaredField("age");
            field.setAccessible(true);
            int age = field.getInt(a);
            System.out.println(age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    如上,如果在声明成员变量时时private的,则用Field对象操作成员变量之前要先执行setAccessible(true)。

  • 相关阅读:
    今日小结
    Delphi 框架Frames的使用
    Delphi窗体显示后弹出一个对话框的方法
    Structs2学习笔记1
    使用 LaravelExcel 进行 CSV/EXCEL 文件读写
    Mysql函数FIND_IN_SET()的使用方法
    Laravel数据库操作的三种方式
    Laravel5.5 支付宝手机网站支付的教程
    Python之路3【知识点】白话Python编码和文件操作
    艾伟_转载:利用jQuery实现的Ajax 验证用户名是否存在 狼人:
  • 原文地址:https://www.cnblogs.com/koushr/p/5873372.html
Copyright © 2020-2023  润新知