利用反射生成实例对象

阅读:298

目录介绍

  • 01.反射生成类实例对象
  • 02.反射调用类的方法
  • 03.反射访问成员变量值
  • 04.访问私有权限说明

01.反射生成类实例对象

  • 生成类的实例对象
    • 1.使用Class对象的newInstance()方法来创建该Class对象对应类的实例。这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。
    • 2.先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。
    //第一种方式 Class对象调用newInstance()方法生成
    Object obj = class1.newInstance();
    //第二种方式 对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成
    Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数
    obj = constructor.newInstance("hello");
    

  • new对象和反射得到对象的区别
    • 在使用反射的时候,必须确保这个类已经加载并已经连接了。使用new的时候,这个类可以没有被加载,也可以已经被加载。
    • new关键字可以调用任何public构造方法,而反射只能调用无参构造方法。
    • new关键字是强类型的,效率相对较高。 反射是弱类型的,效率低。
    • 反射提供了一种更加灵活的方式创建对象,得到对象的信息。如Spring 中AOP等的使用,动态代理的使用,都是基于反射的。解耦。

02.反射调用类的方法

  • 调用类的方法

    • 1.通过Class对象的getMethods()方法或者getMethod()方法获得指定方法,返回Method数组或对象。
    • 2.调用Method对象中的Object invoke(Object obj, Object... args)方法。第一个参数对应调用该方法的实例对象,第二个参数对应该方法的参数。
    private void method8() {
        try {
            Class<?> cl = Class.forName("net.zhifou.other.ui.activity.Student");
            // 生成新的对象:用newInstance()方法
            Student obj = (Student) cl.newInstance();
            String student1 = obj.getStudent();
            LogUtils.i("反射调用类的方法1:"+student1);
            //首先需要获得与该方法对应的Method对象
            Method method = cl.getDeclaredMethod("setAge", int.class);
            //设置权限
            method.setAccessible(true);
            //调用指定的函数并传递参数
            method.invoke(obj, 28);
            String student2 = obj.getStudent();
            LogUtils.i("反射调用类的方法2:"+student2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    

  • 获取方法的参数

  • 当通过Method的invoke()方法来调用对应的方法时,Java会要求程序必须有调用该方法的权限。如果程序确实需要调用某个对象的private方法,则可以先调用Method对象的如下方法。

  • setAccessible(boolean flag):将Method对象的acessible设置为指定的布尔值。值为true,指示该Method在使用时应该取消Java语言的访问权限检查;值为false,则知识该Method在使用时要实施Java语言的访问权限检查。

03.反射访问成员变量值

  • 反射访问成员变量值
    • 1.通过Class对象的getFields()方法或者getField()方法获得指定方法,返回Field数组或对象。
    • 2.Field提供了两组方法来读取或设置成员变量的值:
      • getXXX(Object obj):获取obj对象的该成员变量的值。此处的XXX对应8种基本类型。如果该成员变量的类型是引用类型,则取消get后面的XXX。
      • setXXX(Object obj,XXX val):将obj对象的该成员变量设置成val值。
    private void method9() {
        try {
            Class<?> cl = Class.forName("net.zhifou.other.ui.activity.Student");
            // 生成新的对象:用newInstance()方法
            Student obj = (Student) cl.newInstance();
            int age = obj.getAge();
            LogUtils.i("反射访问成员变量值1:"+age);
            //获取age成员变量
            //Field field = cl.getField("age");
            Field field = cl.getDeclaredField("age");
            //设置权限
            field.setAccessible(true);
            //将obj对象的age的值设置为10
            field.setInt(obj, 10);
            //获取obj对象的age的值
            int anInt = field.getInt(obj);
            LogUtils.i("反射访问成员变量值2:"+anInt);
    
            //反射修改私有变量
            // 获取声明的 code 字段,这里要注意 getField 和 getDeclaredField 的区别
            Field gradeField = cl.getDeclaredField("name");
            // 如果是 private 或者 package 权限的,一定要赋予其访问权限
            gradeField.setAccessible(true);
            // 修改 student 对象中的 Grade 字段值
            gradeField.set(obj, "Hello World");
            Object o = gradeField.get(obj);
            LogUtils.i("反射访问成员变量值3:"+o.toString());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    
    反射访问成员变量值1:26
    反射访问成员变量值2:10
    反射访问成员变量值3:Hello World
    

04.访问私有权限说明

  • 设置暴力访问权限为.setAccessible(true);

赞赏支持


精彩留言

发表评论