反射体系实战
反射技术快速上手
📌 什么是 Java 反射
Java 反射(Reflection)是程序运行时动态获取类信息、构造对象、调用属性 / 方法的机制,核心是操作编译后的Class对象(.class字节码文件的内存表示)。
核心能力
构造任意类的对象
获取对象所属类的完整信息
访问 / 修改类的成员变量(包括私有)
调用类的任意方法(包括私有)
反射核心组件
| 组件 | 含义 |
| Class | 类的字节码对象,反射的源头 |
| Constructor | 类的构造器 |
| Field | 类的成员变量 |
| Method | 类的方法 |
📌 获取 Class 对象的 2 种方式
类名.class(编译期确定)
Class<User> userClass = User.class;
对象.getClass ()(运行期从对象获取)
User user = new User(); Class<? extends User> userClass = user.getClass();
常用 Class API
| 方法名 | 作用 |
| getName() | 获取 包名 + 类名 |
| getSimpleName() | 获取 类名 |
| getDeclaredConstructor(Class<?>... params) | 根据参数类型获取构造器(无视修饰符) |
| getDeclaredConstructors() | 获取所有声明的构造器 |
📌 反射 API 分类:getvsgetDeclared
1.getXxx():获取公有成员
只能获取
public修饰的成员getMethod()会递归查找本类 +父类的公有方法
2.getDeclaredXxx():获取本类所有成员
可以获取
private/protected/public修饰的成员getDeclaredMethod()只查找本类的方法,不查父类
| API 形式 | 访问范围 | 父类可见性 |
| getField() | 仅公有 | 可见(本类 + 父类) |
| getDeclaredField() | 本类所有 | 不可见(仅本类) |
| getMethod() | 仅公有 | 可见(本类 + 父类) |
| getDeclaredMethod() | 本类所有 | 不可见(仅本类) |
💡 为什么要学反射?
是 Java 高级技术、框架底层的标配(Spring、MyBatis 等都依赖反射实现依赖注入、ORM 映射)
阅读源码、编写中间件时必须掌握
实现动态代理、泛型数组创建等高级功能
🎯 示例:获取构造器
// 1. 获取 Class 对象 Class<User> userClass = User.class; // 2. 获取指定参数的构造器 Constructor<User> constructor = userClass.getDeclaredConstructor(int.class, String.class); System.out.println(constructor.getName() + ",参数个数:" + constructor.getParameterCount()); // 3. 获取所有构造器 Constructor<?>[] constructors = userClass.getDeclaredConstructors(); for (Constructor<?> c : constructors) { System.out.println(c.getName() + ",参数个数:" + c.getParameterCount()); }
反射技术实战之对象创建
📌 Constructor 核心作用
Constructor类是反射中用于创建对象的核心 API,最终目的是实例化类对象。
📌 常用newInstance方法
| 方法签名 | 说明 | 要求 |
| T newInstance() | 调用无参构造器创建对象 | 类必须提供 public 权限的无参构造器 |
| T newInstance(Object... initargs) | 调用指定参数构造器创建对象 | 需先获取对应参数列表的 Constructor |
✅ JDK 9 后推荐使用
Constructor.newInstance(),替代旧的Class.newInstance()。
📌 反射创建对象的标准步骤
获取 Class 对象:通过类名
.class或全类名加载获取构造器:调用
getDeclaredConstructor(...)或getConstructor(...)创建对象:调用
constructor.newInstance(...)并传入初始化参数
📌 代码示例
无参构造器创建对象
public static void test2() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 获取无参构造器并创建对象 User user = clazz.getDeclaredConstructor().newInstance(); // 3. 初始化属性 user.setAge(11); user.setName("老王"); System.out.println(user); }
有参构造器创建对象
public static void test3() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 获取指定参数的构造器(int, String) Constructor<User> constructor = clazz.getConstructor(int.class, String.class); // 3. 传入参数创建对象 User user = constructor.newInstance(21, "冰冰"); System.out.println(user); }
📌 为什么 POJO 必须显式写空构造器?
反射创建对象:框架(如 Spring)通过反射调用无参构造器实例化 Bean
子类继承:子类默认调用
super(),父类必须提供无参构造器,否则编译报错
💡 关键注意点
getConstructor(...)只能获取public构造器getDeclaredConstructor(...)可获取所有权限构造器(包括private),需配合setAccessible(true)绕过权限检查无参构造器必须是
public(或通过setAccessible(true)打开权限)才能被newInstance()调用
反射技术实战之方法和属性实战
📌 反射获取方法与属性核心知识点
一、获取类的方法(Method)
| 方法名 | 作用范围 | 权限要求 |
| getMethods() | 当前类 + 父类 | 仅 public 方法 |
| getDeclaredMethods() | 仅当前类 | 所有权限(private/protected/public) |
Method 常用 API:
getReturnType():获取方法返回值类型getParameterTypes():获取方法参数类型数组getModifiers():获取方法修饰符(整数,对应Modifier类常量)getExceptionTypes():获取方法声明抛出的异常类型
代码示例:
public static void test2() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 获取无参构造器并创建对象 User user = clazz.getDeclaredConstructor().newInstance(); // 3. 初始化属性 user.setAge(11); user.setName("老王"); System.out.println(user); }
二、获取类的属性(Field)
表格
| 方法名 | 作用范围 | 权限要求 |
| getFields() | 当前类 + 父类 | 仅 public 属性 |
| getDeclaredFields() | 仅当前类 | 所有权限(private/protected/public) |
Field 常用 API:
getType():获取属性类型getName():获取属性名getModifiers():获取属性修饰符(整数,对应Modifier类常量)
代码示例:
public static void test3() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 获取指定参数的构造器(int, String) Constructor<User> constructor = clazz.getConstructor(int.class, String.class); // 3. 传入参数创建对象 User user = constructor.newInstance(21, "冰冰"); System.out.println(user); }
三、关键区别总结
| API 类型 | getXxx() | getDeclaredXxx() |
| 范围 | 本类 + 父类 | 仅本类 |
| 权限 | 仅 public | 所有权限 |
| 适用 | 方法 / 属性 / 构造器 | 方法 / 属性 / 构造器 |
💡 补充说明
getModifiers()返回的整数可通过Modifier.toString(int mod)转换为可读字符串(如public static final)。若要访问 / 修改私有属性或调用私有方法,需先调用
field.setAccessible(true)或method.setAccessible(true)绕过权限检查。
【重点】保留反射技术实践之属性值操作
📌 反射暴力破解权限:setAccessible(true)
当构造器、方法、属性是private等受限权限时,Java 会阻止直接访问,此时可以通过setAccessible(true)暴力破解权限,Constructor/Method/Field都支持此方法。
🔧 核心 API 说明
| 方法 | 作用 |
| setAccessible(true) | 临时关闭 Java 访问权限检查,允许访问私有成员 |
| Field.get(Object obj) | 获取 obj 对象上该 Field 的属性值 |
| Field.set(Object obj, Object value) | 给 obj 对象上该 Field 设置属性值 |
✅ 案例 1:调用私有构造器创建对象
public static void test4() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 获取私有构造器(无参) Constructor<User> constructor = clazz.getDeclaredConstructor(); // 3. 暴力破解权限 constructor.setAccessible(true); // 4. 创建对象 User user = constructor.newInstance(); user.setAge(11); user.setName("老王"); System.out.println(user); }
✅ 案例 2:操作私有属性(读写)
public static void main(String[] args) throws Exception { // 1. 获取 Class 对象 Class<Product> clazz = Product.class; // 2. 获取私有构造器并创建对象 Constructor<Product> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); Product product = constructor.newInstance(); System.out.println(product); // 初始值:Product(price=0, title='null') // 3. 获取私有属性 title Field titleField = clazz.getDeclaredField("title"); // 4. 破解权限 titleField.setAccessible(true); // 5. 设置属性值 titleField.set(product, "小滴云架构大课"); // 6. 读取属性值 System.out.println(titleField.get(product)); // 输出:小滴云架构大课 System.out.println(product); // 最终:Product(price=0, title='小滴云架构大课') }
⚠️ 关键注意事项
setAccessible(true)是临时生效:仅对当前Constructor/Method/Field对象有效,不会修改类的原始权限。安全风险:破坏封装性,可能导致代码不稳定,框架底层常用,业务代码需谨慎。
适用范围:所有反射成员(构造器、方法、属性)都支持此 API。
💡 总结
权限受限→ 调用
getDeclaredXxx()获取本类私有成员。破解权限→ 调用
setAccessible(true)关闭访问检查。执行操作→ 调用
newInstance()/invoke()/get()/set()完成业务逻辑。
【重点】反射技术之invoke运行类的指定方法
📌 反射运行指定方法:Method.invoke()
反射的最终目的是动态调用类的方法(包括私有方法、静态方法),核心 API 是Method.invoke(Object obj, Object... args)。
🔧invoke方法核心说明
签名:public Object invoke(Object obj, Object... args)
| 参数 | 说明 |
| obj | 调用方法的实例对象;若为静态方法,传 null |
| args | 方法的入参(可变长度);无参则传 null 或省略 |
| 返回值 | 方法的返回值;若无返回值,返回 null |
私有方法调用前提:调用前必须执行method.setAccessible(true)破解权限。
✅ 实战代码示例
调用普通成员方法(含私有)
public static void test7() throws Exception { // 1. 获取 Class 对象 Class<User> clazz = User.class; // 2. 创建对象(若调用非静态方法) Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(); declaredConstructor.setAccessible(true); // 破解私有构造器 User user = declaredConstructor.newInstance(); user.setName("老王"); // 3. 获取指定方法(名称+参数类型) Method sayMethod = clazz.getDeclaredMethod("say", String.class); // 4. 破解权限(如果是私有方法) sayMethod.setAccessible(true); // 5. 调用方法 // 参数1:调用者对象 // 参数2:方法实参 Object returnValue = sayMethod.invoke(user, "大钊老师"); // 6. 处理返回值 System.out.println("方法返回值:" + returnValue); }
调用静态方法
// 获取静态方法 Method sleepMethod = clazz.getDeclaredMethod("sleep", String.class); sleepMethod.setAccessible(true); // 调用静态方法:第一个参数传 null Object result = sleepMethod.invoke(null, "冰冰"); System.out.println("静态方法返回值:" + result);
📝 完整代码模板
// 1. 获取类对象 Class<?> clazz = User.class; // 2. 获取方法对象 Method method = clazz.getDeclaredMethod("方法名", 参数类型.class); // 3. 暴力破解(如果是私有方法) method.setAccessible(true); // 4. 执行方法 // 非静态方法:invoke(对象, 参数) // 静态方法:invoke(null, 参数) Object result = method.invoke(实例对象, 实参);
⚠️ 常见异常与注意事项
NoSuchMethodException:方法名或参数类型不匹配,需仔细核对getDeclaredMethod(name, params)。IllegalAccessException:未调用setAccessible(true)访问私有方法。IllegalArgumentException:传入的对象类型与方法所属类不匹配,或参数类型错误。InvocationTargetException:方法内部执行抛出异常,反射会包装此异常,需通过e.getTargetException()获取真实异常。
💡 核心流程总结
获取 Class→
Class<User> clazz = User.class;获取 Method→
clazz.getDeclaredMethod("say", String.class);破解权限→
method.setAccessible(true);调用 Method→
method.invoke(user, "参数");
