版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lwz45698752/article/details/82849696
文章目录
反射初探
-
反射机制
- 编译时不指定类型,运行时动态获取类型从而进行相应操作(动态性)
- 通过反射动态创建对象
-
一段通用性代码(模板)然后对应数据库,每一条数据看作类的对象
-
代码作用:获取数据库连接 返回一条数据对应的一个对象(相当于在程序中对应一个customer类)
-
根据传入参数,动态创建对应类的对象
-
编译时到字节码文件中,运行时把字节码文件对应的类加载到内存里(运行时加载,即运行时类) --------解释运行时类的由来
-
运行时类的字节码文件对应的类充当Class的实例
-
任何一个类对于反射的Class对象来说是完全暴露的
-
clazz为栈空间的引用,堆空间实体为Person类本身,从而将该类各结构完全暴露
-
调用属性操作
- 首先通过反射获取对应person类的结构信息(如属性)
- f1是name属性引用
- 关注当属性私有公有时不同的调用方法(name共有,age私有)
-
getMethod方法的形参为Class类型,又考虑到display的形参为字符串,所以传入字符串类型的class
Class类
- 返回类对象对应的运行时类(类型为Class)
- 每个类对应一个class文件
- 运行时加载到缓存区(非过河拆桥)
- 只加载一次,所以Class类实例称为获取而不是创建(创建是可多次的,获取只创建一次)
怼到类本身位置上
编译异常要处理
创建Class类对象方法(四种)
- getName为获取类的路径(如className所示)
类的加载器
- 共三种类加载器
- 关注这三种类加载器对应的类
- 字节码文件通过命令解释运行
- 首先装载起来,然后校验和解释
- 加载器:将字节码文件对应结构加载到内存中
类的加载过程
- 类的加载包含三步:如上图
- 类的初始化具体指对静态属性和方法初始化
实例
-
由运行结果知,初始为系统类加载器,获取父类,得扩展类加载器,获取父类,应该得引导类加载器,但该加载器不能获取,返回null
-
系统类加载器负责自定义的类
-
无法获取引导类加载器(核心类库加载自动完成),试图获取则返回null
-
获取加载器的作用在于显式加载某个类
-
加载文件的两种方式
-
法一是获取当前包下创建的文件
-
法二是在在当前文件目录下以流的形式获取一个文件,即在工程下创建
-
创建运行时类的对象
- “==”判断是否指向同一个地址
- 返回皆为true,说明每个类只加载了一次
- Class对象对应加载到内存中的一个类
- 加载到内存中,则创建了对应的Class对象(以后一直在缓存中,供调用)
- 不管直接创建还是通过反射,都是调用类结构中的构造器
- 要求类保留空参构造器,注意权限问题
获取类的结构
获取类属性
- 父类包括间接父类
- 一个是只能获取父类及其本身public属性,一个是本类的所有属性
- 不同修饰符对应不同int值(返回值类型为int),通过toString方法转化
- default权限对应的字符串为空(int id前空缺)
获取类方法
- 关注点类比类属性
- 父类指直接父类及其间接父类
- 方法的异常修饰指的是throws,try/catch块不可见
- 异常和参数获取都是数组返回
获取构造器
- 进一步获取构造器结构类比方法
获取父类及带泛型的父类
- 获取父类采用第一种方法是不带泛型的
获取父类泛型(重点)
- type是个接口,Class实现该接口,所以可以向下转型
- 首先获取带泛型的父类,然后将其强转为子接口,调用该子接口获取泛型的方法,最后强转为Class获取其泛型名
获取实现的接口和所在包
- 获取的接口不包括父接口,只是自身类实现的接口
获取注解
- 只有声明为Runtime的注解才能被反射获取
反射调用类对象的属性
- 关注权限修饰符对反射调用类对象属性的影响(declared得到的属性要特别考虑权限问题)
反射调用方法
- 只能获取声明为public方法
- invoke方法返回值即实际调用的方法返回值
反射调用构造器
- 关注int.class(参数为int类型,同时要求传入Class类型参数)
- declared和setAccessible配套使用