每次用 Java 反射调一个方法,你都得写一堆 getDeclaredMethod、setAccessible、invoke,还要处理 ClassNotFoundException、NoSuchMethodException……一个调用撑起十行代码,读起来像在解谜。EggG 提供了一套流式反射 API,把这套仪式感压缩成链式调用,一行搞定。
传统反射到底有多啰嗦
先看一个真实场景:用反射创建 Person 对象并调用其 sayHello 方法。
// 传统写法:10+ 行只为调一个方法
Class<?> clazz = Person.class;
Constructor<?> ctor = clazz.getConstructor(String.class, int.class);
Object person = ctor.newInstance("张三", 25);
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(person, "世界");
System.out.println(result); // "张三说:你好,世界"
问题不止是行数——每个中间变量都可能抛异常,try-catch 嵌套下去更膨胀。而且 setAccessible 在 JDK 9+ 模块系统下还可能被拦截,错误处理路径复杂。
EggG 的流式写法
同一个调用,EggG 的写法:
// EggG 流式写法
Object result = Reflect.on(Person.class)
.create("张三", 25)
.call("sayHello", "世界")
.get();
System.out.println(result); // "张三说:你好,世界"
从声明类、构造对象、调用方法到取返回值,一条链走完。没有中间变量,没有手动 setAccessible,异常也被框架统一包装。
核心操作速查
EggG 的 API 围绕 Reflect.on() 入口展开,几个高频操作如下:
| 操作 | 传统写法要点 | EggG 写法 |
|---|---|---|
| 创建实例 | getConstructor + newInstance |
.create(参数...) |
| 调方法 | getDeclaredMethod + setAccessible + invoke |
.call("方法名", 参数...) |
| 读字段 | getDeclaredField + setAccessible + get |
.field("字段名").get() |
| 写字段 | getDeclaredField + setAccessible + set |
.field("字段名").set(值) |
| 访问私有成员 | 手动 setAccessible(true) |
自动处理 |
实战示例:绕过框架限制修改配置
假设你在测试环境需要修改一个第三方库的 private static 配置值,传统方式要处理 Field 的修饰符限制(final 字段尤其麻烦)。用 EggG:
import com.eggg.reflect.Reflect;
// 目标:修改 Config 类的 private static final MAX_RETRY 字段
// 传统写法需要处理 modifiers 字段来移除 final,代码量 15+ 行
// EggG 写法:
Reflect.on(Config.class)
.field("MAX_RETRY")
.set(10); // 原值 3,改为 10
// 验证
int newVal = Reflect.on(Config.class)
.field("MAX_RETRY")
.get();
System.out.println(newVal); // 10
运行前注意:
- 引入 EggG 依赖(Maven):
<dependency>
<groupId>com.eggg</groupId>
<artifactId>reflect</artifactId>
<version>最新版本</version>
</dependency>
- JDK 9+ 模块系统下,如果目标类在非开放模块中,仍需添加
--add-opensJVM 参数,EggG 无法绕过 JVM 层面的模块访问控制。 - 修改
static final字段在 JDK 12+ 可能因内联优化而无效,生产环境慎用。
链式调用的组合场景
更复杂的场景——反射调用链式方法、访问嵌套对象:
// 假设 Person 有 getDepartment() → Department 有 getName()
// 传统写法:两次 getDeclaredMethod + 两次 invoke,还要类型转换
String deptName = Reflect.on(Person.class)
.create("李四", 30)
.call("getDepartment")
.call("getName")
.get();
System.out.println(deptName); // "研发部"
链式调用自动传递上一步的返回值作为下一步的目标对象,省掉了手动类型转换和中间变量。
采纳建议与边界
适合用 EggG 的场景:
- 单元测试中需要 mock 私有方法或注入私有字段
- 框架开发中需要动态访问用户定义的类成员
- 临时脚本/调试工具中快速探查对象内部状态
不适合的场景:
- 高频热路径调用——反射本身比直接调用慢 10-100 倍,流式包装再叠加一层对象创建,性能敏感代码别用
- 生产环境修改
final常量——JVM 内联优化可能导致修改"看不见" - 安全审计严格的系统——
setAccessible绕过访问控制可能违反安全策略
迁移检查清单:
- [ ] 确认项目 JDK 版本,8 无模块问题,9+ 需检查
--add-opens - [ ] 性能敏感路径排除反射调用,只在启动/测试阶段使用
- [ ] 将现有
try-catch块替换为 EggG 的ReflectException统一捕获 - [ ] 私有字段操作加注释标记,方便后续代码审查定位
EggG 不是让反射变快,而是让反射变短。当你确实需要反射时,少写八行代码、少声明三个中间变量,本身就是收益。