zoukankan      html  css  js  c++  java
  • 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()执行某个实例的方法
  • 相关阅读:
    Enhancing State-of-the-art Classifiers with API Semantics to Detect Evolved Android Malware论文阅读笔记
    this和super的总结
    软件工程结对WordCount项目
    软工个人作业 数独
    问题
    自我介绍
    shuduku
    access to DeepLearning
    自我介绍
    学习软工基目标
  • 原文地址:https://www.cnblogs.com/yokii/p/9451578.html
Copyright © 2011-2022 走看看