反射机制(笔记)
一、反射的基本概念
1.1. 反射机制的应用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
1.2. 反射相关api
java,lang.class: 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Constructor: 代表类的构造器
... ...
1.3. 反射的优缺点
优点:
- 提高了Java程序的灵活性和扩展性,降低了拥合性,提高 自适应能力
- 允许程序创建和控制任何类的对象,无需提前 硬编码 目标类
缺点:
- 反射的性能较低。
- 反射机制主要应用在对灵活性和扩展性要求很高的系统框架上
- 反射会 模糊 程序内部逻辑,可读性较差 。
二、Class类的理解与类的加载
2.1. CLass类的理解
针对于编写好的.java源文件进行编译(使用javac.exe),会生成一个或多个.class字节码文件。接着,我们使用java.exe命令对指定的.class文件进行解释运行,这个解释运行的过程中,我们需要将class字节码文件加载(使用类的加载器)到内存中(存放在方法区)。加载到内存中的.class文件对应的结构即为CLass的一个实例。
比如,加载到内存中的Person类或string类或User类,都作为class的一个一个的实例
2.2. 获得CLass类的几种方式
//1。调用运行时类的静态何性: cLass
Class clazz1 = User.class;
System.out.println(clazz1);
//2. 调用运行时类的对象的getCLass()
User u1 = new User();
Class clazz2 = u1.getClass();
//3. 调用CLass的静态方法forName(String className)
String className = "com.tp._class.User"; //全类名
Class clazz3 = Class.forName(className);
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
//4. 使用类的加载器的方式 (了解)
Class clazz4 = ClassLoader.getSystemClassLoader().loadClass(className);
System.out.println(clazz1 == clazz4);//true
三、反射的应用
3.1. 创建运行时类的对象
3.1.1. 如何实现
通过Class的实例调用newInstance()方法即可
3.1.2. 需要满足什么条件
- 要求运行时类中必须提供一个空参的构造器
- 要求提供的空参的构造器的权限要足够
- public修饰符
- 默认修饰符,但必须在同一个包下
3.1.3. 在jdk9中标识为过时,替换成什么结构
通过Constructor类调用newInstance(...)
3.2. 获取运行时类的内部结构
3.2.1. 获取所有属性、所有方法、所有构造器(了解)
Class clazz = Person.class;
//getFields(): 获取到运行时类本身及其所有的父类中声明为public 权限的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
//getDecLaredFieLds():获取当前运行时类中声的所有属性
Field[] decLaredFields = clazz.getDeclaredFields();
for(Field f : decLaredFields) {
System.out.println(f);
}
3.2.2. 获取父类、结构们、包、带泛型的父类、父类的泛型等
Class clazz = Class.forName( "com.tp._class.Person");
// 1.获取运行时类的父类
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
// 2.获取运行时类的带泛型的父类
Type superclass = clazz.getGenericSuperclass();
System.out.println(superclass);
// 3.获取运行时类实现的接口
Class[] interfaces = clazz.getInterfaces();
for (Class c : interfaces) {
System.out.println(c);
}
// 4.获取运行时类所在的包
Package pack = clazz.getPackage();
System.out.println(pack);
// 5.获取运行时类的父类的泛型
//如果父类是带泛型的,则可以强转为ParameterizedType
ParameterizedType paramType = (ParameterizedType) superclass;
//调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数。
Type[] arguments = paramType.getActualTypeArguments();
// 获取泛型参数的名称
System.out.println(((Class)arguments[0]).getName());