1,概述
在程序的运行过程中, 通过Class对象得到类中的信息(构造方法, 成员方法, 成员变量), 并操作他们
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。非常规的手段操作对象。
Class类
java中存在一个类叫Class类,Class类创建的对象我们称为Class对象/类对象
Class对象会保存类中的信息(构造方法, 成员方法, 成员变量等)
有了Class对象就能得到类中的所有信息。可以说得到Class对象反射就完成了一半。
反射的应用场景
- ①IDEA的智能提示
- ②框架Spring/SpringMVC/Mybatis
利用反射调用它类中的属性和方法时,无视修饰符使用反射创建对象,代码更复杂功能更强大灵活,会破坏封装
三种获取Class对象的方式
- 类名.class
- 对象.getClass()
- Class.forName(“类全名”);
常用方法
| 方法 | 说明 |
|---|---|
| String getSimpleName(); | 获得类名字符串:类名 |
| String getName(); | 获得类全名:包名.类名 |
| T newInstance | 通过Class对象创建对象 |
| 操作构造器对象 | |
| Constructor<?>[] getConstructors() | 返回所有构造器对象的数组(只能拿public的) |
| Constructor |
返回单个构造器对象(只能拿public的) |
| Constructor<?>[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
| Constructor |
返回单个构造器对象,存在就能拿到 |
| 构造器对象方法 | |
| T newInstance(Object… initargs) | 根据指定的构造器创建对象 |
| public voidsetAccessible(boolean flag) | 设置为true,表示取消访问检查,进行暴力反射 |
| 操作成员方法对象 | |
| Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
| Method getMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象(只能拿public的) |
| Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
| Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
| 成员方法对象的方法 | |
| Object invoke(Object obj, Object… args) | 运行方法 参数一:方法的调用者 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
| 操作成员变量 | |
| Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
| Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
| Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
| Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
| 成员变量方法 | |
| void set(Object obj, Object value): | 赋值 |
| Object get(Object obj) | 获取值 |
注意:反射中方法参数类型若是泛型,则需要传入Object.class
2,动态代理
代理模式三要素
你 -> 黄牛-> 12306买票
- 真实对象: 真正工作的对象12306
- 代理对象: 黄牛
- 抽象对象: 代理对象和真实对象都要实现的接口 (卖票接口)
什么是动态代理?在程序的运行过程中创建出代理对象
动态代理的好处:可以对功能进行增强或拦截
Proxy类
介绍:动态代理类
常用构造
| 方法 | 说明 |
|---|---|
| public static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) |
创建代理对象 参数: ClassLoader loader: 类加载器, 固定写法 当前类名.class.getClassLoader() Class<?>[] interfaces: 多个接口, 代理对象会实现这些接口 InvocationHandler h: 执行处理器接口, 放入匿名内部类 |
示例
需求:统计list方法的执行时间,拦截remove方法
public class TestCode {public static void main(String[] args) {// 创建真实对象ArrayList<Integer> list = new ArrayList<>();// 创建动态代理对象Object proxy = Proxy.newProxyInstance(// 固定写法TestCode.class.getClassLoader(),// 代理对象需要实现的接口new Class[]{List.class},// 代理对象调用任何方法都会执行invoke// invoke相当于重写了接口的所有方法,可以做统一处理new InvocationHandler() {@Override //代理对象 调用方法 参数public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 对方法进行拦截if (method.getName().equals("remove")) {System.out.println("已拦截remove方法");return null;}// 对方法进行增强long start = System.currentTimeMillis();// 相当于list.add(1) 方法名.调用(调用者,参数)Object res = method.invoke(list, args);long end = System.currentTimeMillis();System.out.println(method.getName() + "耗时" + (end - start) + "ms");return res;}});List plist = (List) proxy;plist.add(1);plist.add(2);System.out.println(plist);plist.remove(1);System.out.println(plist);}}
