07-进阶技术—反射


前言

  • 反射的概述:
    • 允许对封装类的字段、方法和构造函数的信息进行编程访问
    • 允许对成员变量、成员方法和构造方法的信息进行编程访问

在这里插入图片描述

一、反射机制

  • 反射机制
    是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
    对于任意一个对象,都能够调用它的任意属性和方法;
    这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
    在这里插入图片描述

二、获取Class类对象的三种方式

2.1 三种方式概述

  • 三种方式分类:——> 都是获取某类的字节码文件对象

    • 类名.class属性
    • 对象名.getClass()方法
    • Class.forName(全类名)方法
  • 图解:
    在这里插入图片描述

  • 应用场景
    在这里插入图片描述

2.2 反射获取构造方法并使用——Constructor

2.2.1 Class类获取构造方法对象的方法

  • 方法介绍

    方法名说明
    Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
    Constructor<?>[] getDeclaredConstructors()返回所有(任何权限修饰符修饰的)构造方法对象的数组
    Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
    Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个(任何权限修饰符修饰的)构造方法对象
  • 获取构造方法对象的步骤
    因为构造方法是在字节码文件中,因此首先都要获取到字节码文件对象

    • 获取class字节码文件对象
      在这里插入图片描述
      用获取到的字节码文件对象调用方法来获取想要的构造方法
      在这里插入图片描述

2.2.2 Constructor类用于创建对象的方法

  • 方法介绍

    方法名说明
    T newInstance(Object…initargs)根据指定的构造方法创建对象
    setAccessible(boolean flag)设置为true,表示取消访问检查
  • 方法setAccessible(boolean flag)
    在这里插入图片描述

注意:创建被私有的对象需要先临时取消权限校验后才能使用newInstance(Object…initargs)方法进行创建对象

在这里插入图片描述

2.2.3 小结

  • 获取class对象
    三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()

  • 获取里面的构造方法对象
    getConstructor (Class<?>... parameterTypes) getDeclaredConstructor (Class<?>… parameterTypes)

  • 如果是public的,直接创建对象
    newInstance(Object… initargs)

  • 如果是非public的,需要临时取消检查,然后再创建对象
    setAccessible(boolean) 暴力反射
    在这里插入图片描述

2.3 反射获取成员变量并使用——Field

2.3.1 Class类获取成员变量对象的方法

  • 方法分类

    方法名说明
    Field[] getFields()返回所有公共成员变量对象的数组
    Field[] getDeclaredFields()返回所有成员变量对象的数组
    Field getField(String name)返回单个公共成员变量对象
    Field getDeclaredField(String name)返回单个成员变量对象
  • 方法示例
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

2.3.2 Field类用于给成员变量赋值的方法

  • 方法介绍
方法名说明
void set(Object obj, Object value)赋值
Object get(Object obj)获取值

在这里插入图片描述

2.4 反射获取成员方法并使用——Method

2.4.1 Class类获取成员方法对象的方法

  • 方法分类

    方法名说明
    Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
    Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
    Method getMethod(String name, Class<?>… parameterTypes)返回单个公共成员方法对象
    Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象
  • 方法示例
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2.4.2 Method类用于执行方法的方法

  • 方法介绍

    方法名说明
    Object invoke(Object obj, Object… args)运行方法

    参数一: 用obj对象调用该方法
    参数二: 调用方法的传递的参数 (如果没有就不写)
    返回值: 方法的返回值 (如果是void就不写)

  • 方法示例
    在这里插入图片描述
  • 如果运行的方法有返回值
    在这里插入图片描述

三、代码示例

  • 学生类
package com.wedu.fanshe;

public class Student {
    private String name;
    private int age;
    private String number;


    public Student() {
    }

    private Student(String name){
        this.name = name;
    }

    protected Student(int age){
        this.age = age;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    private void show1(){
        System.out.println("这是私有方法");
    }
    private String show(int b){
        System.out.println("这是私有方法,有返回值");
        System.out.println("参数数据为:"+b);
        return "执行";
    }

    private void show2(String str,String arr){
        System.out.println("这是公共方法"+str);
    }


    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
  • 测试类
package com.wedu.fanshe;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class FansheDemo01 {
    public static void main(String[] args) throws Exception {
        /**
         * 获取com.wedu.fanshe包下的Student类的字节码文件对象
         * 使用的是  Class.forName(全类名)方法
         */
        Class<?> aClass = Class.forName("com.wedu.fanshe.Student");


        /*
        * 构造方法的反射应用
        */
        Constructor<?>[] constructors = aClass.getConstructors();//获取该类所有公共的构造方法
        for (Constructor<?> constructor : constructors) {
            System.out.println("公共:"+constructor);

            int modifiers = constructor.getModifiers();//调用该方法可以返回不同修饰符关键字的常量字段值
            System.out.println("修饰符的常量字段值为:"+modifiers);
        }

        //获取 该类形参为String,且只有String 的构造方法
        Constructor<?> dConstructor = aClass.getDeclaredConstructor(String.class);
        System.out.println(dConstructor);
        System.out.println("私有构造的常量字段值为:"+dConstructor.getModifiers());

        Constructor<?> dC = aClass.getDeclaredConstructor(String.class, int.class);

        /**
         * 用字节码文件对象得到的相应构造方法对象调用.getParameters()方法
         * 获取该构造方法对象的所有形参中的成员变量(因为调用者是构造方法对象)
         *
         *          该方法的调用者是谁 就返回谁的所有参数的对象
         *   例:获取到的方法的对象m m.getParameters() ——> 返回方法内的所有参数,包括参数类型和参数名
         */
        Parameter[] parameters = dC.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(dC+"中的参数:"+"\t"+parameter);
        }

        System.out.println("============================");
        /*
        * 成员变量的反射应用
        */

        Field[] fields = aClass.getFields();//获取所有公共成员变量对象
        for (Field field : fields) {
            System.out.println("所有公共成员变量:"+field);
        }

        //获取指定的单个成员变量对象(公共、私有都可)
        Field number = aClass.getDeclaredField("number");
        System.out.println("成员变量全称为:"+number);

        System.out.println("指定成员变量的名字为:"+number.getName());
        System.out.println("指定成员变量的类型为:"+number.getType());

        Field name = aClass.getDeclaredField("name");

        /*
       * 获取已有的学生对象的某个成员变量的值
       * 先根据获取到的构造方法 暴力反射创建学生对象
       */
        dC.setAccessible(true);//临时取消权限校验
        //  dC  ——>  上面获取到的 学生类的有参构造方法 的对象
        Student stu = (Student) dC.newInstance("张三", 22);
        System.out.println("修改前:"+stu);

        //获取学生对象的指定变量的值
        name.setAccessible(true);//每暴力反射一次,都需要临时取消权限
        String stuName = (String) name.get(stu);//因为返回值为Object类型的对象,但是已知返回的是字符串类型,因此直接强转即可
        System.out.println("获取到stu对象的name的值,即该学生对象的姓名为:"+stuName);

        //为指定学生对象的成员变量赋值
        name.set(stu,"李四");
        System.out.println("修改后:"+stu);

        System.out.println("==============================");

        /*
        * 成员方法的反射应用
        */

        //获取该类所有公共成员方法对象,包括继承的父类的公共方法
        Method[] methods = aClass.getMethods();
        System.out.println("所有公共方法展示:");
        for (Method method : methods) {
            System.out.println(method);
        }

        //获取指定的单个成员方法对象
        Method show2 = aClass.getDeclaredMethod("show2",String.class,String.class);
        //                                              注意:实体类该方法中有几个形参 此处就应该有几个xx.class
        System.out.println("已找到指定成员方法对象,是:\t"+show2);

        Parameter[] parameters1 = show2.getParameters();
        System.out.println("这是show2方法对象的所有形参对象:");
        for (Parameter parameter : parameters1) {
            System.out.println(parameter);
        }

        Method show = aClass.getDeclaredMethod("show",int.class);
        System.out.println("已找到指定成员方法对象2,是:\t"+show);

        //用反射来执行学生类中的私有方法
        Student student = new Student();
        //如果该方法是私有的 即需要临时取消权限 反之不需要
        if(show.getModifiers()!=1){
            //获取该方法的常量字段值 —— public的常量字段值为1

            show.setAccessible(true);//临时取消权限校验

            Object result=show.invoke(student,44);
            System.out.println("已运行,返回值为:"+result);
        }else {
            Object result=show.invoke(student,44);
            System.out.println("已运行,返回值为:"+result);
        }



    }
}

反射的作用

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值