021.day21 反射 Class类 反射常用操作

目录

反射

一、可变参数

从JDK5开始,可以允许方法定义长度可变的参数

// 可以看做数组
public void func(int ... args){
        
}
  • 调用方法时可以将参数罗列传入也可以直接传入数组
  • 可变参数的定义只能放在参数列表的最后
  • 一个方法最多只能有一个长度可变参数

二、反射

指程序可以访问、检测和修改其本身状态或行为的一种能力,增强了程序的灵活性和
可移植性

1. 反射的作用

  • 运行时构造一个任意类的对象
  • 运行时判断任意一个类所具有的成员变量和方法
  • 运行时调用任意一个对象的方法,包括使用私有声明的方法

2. 反射常用API

  • Class类:代表一个类
  • Field类:代表类的成员变量
  • Method类:代表类的成员方法
  • Constructor类:代表类的构造方法

三、Class类

Class类是反射机制的入口

  • 每个类都能够获得相应的Class对象
  • 可以用于获取与类结构相关的信息
  • 继承Object类

1. Class类存放的结构信息

  • 类的相关信息:父类,接口,名称等
  • 属性
  • 方法
  • 构造方法

2. 获取Class对象的方式

获取Class的三种方式
1.类.class - 编译阶段 - 编译的文件中读取
2.实例.getClass() - 运行阶段 - new 实例 -> 静态代码块、动态代码块、构造器
3.Class.forName(String name) - 运行阶段 - 静态代码块

  • 通过对象获得
Student stu=new Student();
Class clazz=stu.getClass();
  • 通过类获得
Class clazz=Student.class;
  • 通过forName方法获得
Class clazz = Class.forName("com.qfedu.bean.Student");

3. 获取其他结构的方式

Class clazz = Class.forName("java.lang.Object");
  • 获取成员属性
Field fields[ ] = clazz.getDeclaredFields();
  • 获取成员方法
Method methods[] = clazz.getDeclaredMethods();
  • 获取构造器
Constructor constructors[ ] = clazz.getDeclaredConstructors();
// TODO 获取类的结构信息
        Class<Student> studentClass = Student.class;
        System.out.println(studentClass.getName());
        // 获取构造器的对象
        Constructor[] constructor1 = studentClass.getConstructors();
        Constructor[] constructor2 = studentClass.getDeclaredConstructors();
        // 获取成员变量
        Field[] field1 = studentClass.getFields();
        Field[] field2 = studentClass.getDeclaredFields();
        // 获取方法
        // 包括超类中声明的方法,没有私有方法
        Method[] method1 = studentClass.getMethods();
        // 可以查看私有方法,不包括本类之外的
        Method[] method2 = studentClass.getDeclaredMethods();
// TODO 获取类的相关信息
        Class<Student> studentClass = Student.class;
        // 父类信息
        System.out.println(studentClass.getSuperclass());
        // 实现的接口
        System.out.println(studentClass.getInterfaces()[0]);
        // 所在的包
        System.out.println(studentClass.getPackage().getName());
// TODO 构造器 -> 返回新的实例 (企业级封装)
        // 1.获得Class
        Class<?> studentClass = Class.forName("com.qfedu.bean.Student");
        // 2.遍历构造器
        Constructor<?>[] constructors = studentClass.getConstructors();
        // 定义一个map结构记录每种构造器对应的参数列表
        Map<String, Class<?>[]> arg = new HashMap<>();
        // constructor:每次获取到的构造器
        for (Constructor<?> constructor : constructors) {
            // 定义一个数组记录当前构造器的参数列表(顺序及类型)
            Class<?>[] temp = new Class[constructor.getParameterTypes().length];
            // 定义一个变量记录顺序 - 同时控制下标
            int i = 0;
            // 3.遍历参数列表
            // clazz:每次获取到相应的类型
            for (Class<?> clazz : constructor.getParameterTypes()) {
                // 将当前参数类型放入数组
                temp[i++] = clazz;
            }
            // 将当前构造器对应的参数列表存入map
            // key:构造器描述信息 - 权限修饰符 构造器全称 [参数列表]
            // value:构造器的参数列表
            arg.put(constructor.toString(), temp);
        }
        // 4.获得到一个确切的构造器对象 - 使用通用的方式记录参数列表以及使用的需要进行确定
        // 定义一个字符串 - 准备记录匹配到的构造器描述信息(也可能没有匹配)
        String key = "";
        // list集合中记录了传入的零散信息 - 如:接收的数据
        ArrayList<Class<?>> condition = new ArrayList<>();
        // 添加模拟数据
        condition.add(String.class);
        condition.add(Integer.class);
        for (Map.Entry<String, Class<?>[]> entry : arg.entrySet()) {
            boolean flag = true;
            for(int i = 0;i < entry.getValue().length;i ++) {
                if (!entry.getValue()[i].getName().equals(condition.get(i).getName())) {
                    flag = false;
                }
            }
            if (flag) {
                key = entry.getKey();
            }
        }
        System.out.println(key);
        // 通过参数类型来判断 - 通过value检索 - 匹配相应key - 遍历entrySet
        // 向不定参数的方法传递参数时 - 数量不确定时
        // 1.罗列方式传入
        // 2.数组方式传递
        Constructor<?> constructor2 = studentClass.getConstructor(arg.get(key));
        // 4.通过无参的构造器返回新的实例
        System.out.println(constructor2.newInstance("sand",20));

四、反射常用操作

1. 动态创建对象

  • 使用newInstance()方法,仅能调用无参构造方法
Class clazz=Class.forName("com.qfedu.Student");
Object obj=clazz.newInstance(); 
  • 使用Constructor的newInstance()方法,可以调用所有的构造方法
Class clazz=Class.forName("com.qfedu.Student");
Constructor<Student> constructor = clazz.getConstructors()[0];
Object obj=constructor.newInstance();   

2. 动态操作属性

  • 获取所有的Filed对象:getDeclaredFields()/getFields()
  • 通过对象的简称获得Field对象:getDeclaredField(String name)/getField(String name)

3. 动态执行方法

  • 获取所有的Method对象:getDeclaredMethods()/getMethods()
  • 通过方法名称和参数列表获得Method对象:getMethod(String name, Class<?>... parameterTypes)/getDeclaredMethod(String name, Class<?>... parameterTypes)
  • 使用invoke()执行某个实例的方法

猜你喜欢

转载自www.cnblogs.com/yokii/p/9451578.html