当前位置: 首页 > news >正文

反射体系实战

反射技术快速上手

📌 什么是 Java 反射

Java 反射(Reflection)是程序运行时动态获取类信息、构造对象、调用属性 / 方法的机制,核心是操作编译后的Class对象(.class字节码文件的内存表示)。

核心能力
  • 构造任意类的对象

  • 获取对象所属类的完整信息

  • 访问 / 修改类的成员变量(包括私有)

  • 调用类的任意方法(包括私有)

反射核心组件
组件含义
Class类的字节码对象,反射的源头
Constructor类的构造器
Field类的成员变量
Method类的方法

📌 获取 Class 对象的 2 种方式

  1. 类名.class(编译期确定)

Class<User> userClass = User.class;

  1. 对象.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()


📌 反射创建对象的标准步骤

  1. 获取 Class 对象:通过类名.class或全类名加载

  2. 获取构造器:调用getDeclaredConstructor(...)getConstructor(...)

  3. 创建对象:调用constructor.newInstance(...)并传入初始化参数


📌 代码示例

  1. 无参构造器创建对象

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); }

  1. 有参构造器创建对象

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。


💡 总结

  1. 权限受限→ 调用getDeclaredXxx()获取本类私有成员。

  2. 破解权限→ 调用setAccessible(true)关闭访问检查。

  3. 执行操作→ 调用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)破解权限。


✅ 实战代码示例

  1. 调用普通成员方法(含私有)

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); }

  1. 调用静态方法

// 获取静态方法 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(实例对象, 实参);


⚠️ 常见异常与注意事项

  1. NoSuchMethodException:方法名或参数类型不匹配,需仔细核对getDeclaredMethod(name, params)

  2. IllegalAccessException:未调用setAccessible(true)访问私有方法。

  3. IllegalArgumentException:传入的对象类型与方法所属类不匹配,或参数类型错误。

  4. InvocationTargetException:方法内部执行抛出异常,反射会包装此异常,需通过e.getTargetException()获取真实异常。


💡 核心流程总结

  1. 获取 ClassClass<User> clazz = User.class;

  2. 获取 Methodclazz.getDeclaredMethod("say", String.class);

  3. 破解权限method.setAccessible(true);

  4. 调用 Methodmethod.invoke(user, "参数");

http://www.cnnetsun.cn/news/1309590.html

相关文章:

  • CLIP-GmP-ViT-L-14算法精讲:深入理解对比学习与图文预训练核心技术
  • 第 178 场双周赛Q1:101014. 找到第一个唯一偶数
  • 基于RA - AF的高斯混合聚类裂纹模式识别:MATLAB实现
  • java8案例对list[过滤、分组,转换,查找等]清洗逻辑
  • Csimplecleaner:C盘维护与空间管理的最佳实践
  • 智能科学与技术毕业设计2026开题指导
  • LeetCode热题100 括号生成
  • 项目实训。
  • 开关磁阻电机SRM12-8技术详解:额定功率达2200w,转速稳定达额定转速3450rpm
  • MATLAB环境下基于随机游走拉普拉斯算子的快速谱聚类方法 算法运行环境为MAYLAB R2018A
  • 神经网络PID控制BP_PID,模糊PID控制等Matlab/SImulink建模仿真
  • 2026-03-16 GitHub 热点项目精选
  • 计算机文件基础:从概念到路径实践
  • 螺杆式空压机工频运行,变频机不能用使用西门子224xp 十昆仑通态触摸屏,程序有注释
  • KEPServerEX 6.6中文版下载|稳定运行|含详细安装与教程
  • 【什么是二叉树?什么是二叉堆?】
  • 冒泡,选择,插入排序再学习
  • 【全网首家】·openclaw开发的GEO优化系统|小龙虾GEO系统|小龙虾专属GEO优化助理
  • TensorFlow eager模式超流畅
  • ARM Cortex‑M带U大介绍,内核都带啥U!
  • 视频如何防盗录传播.使用加密软件,轻松几步就可以解决烦恼
  • 制造业信息化系统开发工程师 - 学习资料汇总
  • 《低电压设计必看!轨到轨运放选型、电路搭建与常见坑避坑手册》
  • 不只是调包:Transformer编码器的原理与实现(一)
  • Linux系统重置root(破解密码)
  • JavaScript性能优化实战辰姿
  • TCP/IP网络-网络接口层标准
  • 黄仁勋发布万字长文:AI是一个五层蛋糕,万亿建设量还在后面
  • c语言初学
  • 编译器扩展与C++兼容性