目录
一、反射:Reflection
反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射机制提供的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 生成动态代理
反射相关的API:
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法
二、反射源头:java.lang.Class
1.Class类:
特点:
- Class本身也是一个类
- Class对象只能有系统建立对象
- 一个类在JVM中共只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类中的完整结构
通过对象反射求出类名示例:
2.类的加载、连接、初始化:
当程序使用某个类,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三个步骤来对该类进行初始化。如无意外,JVM会连续完成这三个步骤,所有有时也成为类加载或类初始化。
类加载:
将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说,当程序使用任何类时,系统都会为之创建一个java.lang.Class对象。
系统中所有类实际上也是对象,他们都是java.lang.Class的实例
由类加载器完成的。
类的连接:
连接负责把类的二进制数据合并到JRE中,分为3阶段:
- 验证:验证阶段用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
- 准备:类准备阶段则负责为类的类变量分配内存,并设置默认初始化
- 解析:将类的二进制数据中的符号引用替换成直接引用
类的初始化:
主要对类变量进行初始化。
类加载器:ClassLoader
将类的class文件读入内存,并为之创建一个java.lang.Class对象
Class的实例
每个类被加载之后,系统就会为改类生成一个对应的Class对象,通过改Class对象就可以访问到JVM中的这个类。
我们创建一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)。此.class文件加载到内存以后,就是一个运行时类,放在缓存区。那么这个运行时类本身就是一个Class的实例!
每个运行时类只加载一次
有了Class的实例以后,我们才可以进行如下操作:
- *创建对应的运行时类的对象。
- 获取对应的运行时类的完整解雇(属性、方法、构造器、内部类、父类、所在的包、异常、注解...)
- *调用对应的运行时类指定的结构(属性、方法、构造器)
- 反射的应用:动态代理
如何获取Class的实例
- 调用运行时类本身的.class属性
- 通过运行时类的对象获取
- 通过Class 的静态方法获取
- 通过类的加载器
@Test
public void test4() throws ClassNotFoundException{
// 1.调用运行时类本身的.class属性
Class clazz = Person.class;
System.out.println(clazz.getName());
Class clazz2 = String .class;
// 2. 通过运行时类的对象获取
Person p = new Person();
Class clazz3 = p.getClass();
// 3.通过Class 的静态方法获取
String className = "com.taiheyule.yinghe.Person";
Class clazz4 = Class.forName(className);
// 4.通过类的加载器(了解)
String className1 = "com.taiheyule.yinghe.Person";
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz5 = classLoader.loadClass(className1);
}
Class的实例能干什么?
创建运行时类的对象
调用Class对象的newInstance():
要求:
- 类必须有一个无参的构造器。
- 类的构造器访问权限足够。
@Test
public void test6() throws Exception{
String className ="com.taiheyule.yinghe.Person";
Class clazz = Class.forName(className);
// 创建对应的运行时类的对象,newINnstance()调用的是运行时类的空参构造器,构造器的权限要足
Object obj = clazz.newInstance();
Person p = (Person)obj;
System.out.println(p);
}
获取运行时类的完整结构
运行时类的属性:
运行时类的方法:
***通过反射调用类的方法、属性
调用属性:
调用方法:
三、反射的应用:
动态代理与AOP