java反射调用方法慢的根本原因是绕开编译期绑定和jit优化,每次invoke需查找、校验、jni跳转;缓存method、预设setaccessible(true)、改用methodhandle或生成字节码可显著提升性能。

Java 反射调用方法慢,根本原因不是“反射本身写得差”,而是它被迫绕开编译期绑定和 JIT 优化,在每次 invoke() 时都要做查找、校验、JNI 跳转。单次调用比直接调用慢 50–60 倍,高频场景(如 JSON 反序列化、ORM 字段赋值、批量 Bean 拷贝)会立刻暴露瓶颈。
缓存 Method 对象,避免重复查找
最常见也最有效的第一步:把 Class.getMethod() 的结果存起来,别每次调用都重新扫描继承链、匹配参数类型、做字符串比对。
- 用
ConcurrentHashMap按类+方法名+参数类型签名缓存,首次访问稍慢,后续几乎零开销 - 不要在循环里写
obj.getClass().getMethod("xxx")—— 这是性能杀手 - 静态初始化块或 Spring @PostConstruct 中预加载常用 Method,启动时完成解析
提前设 setAccessible(true),跳过安全检查
每次 method.invoke() 都会触发 JVM 的访问控制校验逻辑,哪怕没启用 SecurityManager,这部分开销也照常发生。
- 对私有/包级方法,获取 Method 后立即调用
setAccessible(true) - 这个操作只需一次,之后所有
invoke()都省掉权限判断,实测提速约 40% - 注意:JDK 12+ 在强封装模块下需额外配置
--add-opens,否则会抛InaccessibleObjectException
用 MethodHandle 替代 Method.invoke()
MethodHandle 是 JVM 更底层的调用机制,设计目标就是高性能反射。它支持预绑定、可被 JIT 内联,调用开销远低于 Method.invoke()。
- 通过
MethodHandles.lookup().findVirtual()获取句柄,之后像普通函数一样调用 - 比
Method.invoke()快 2–3 倍,且随调用次数增加,JIT 会持续优化 - 适合需要动态但又要求稳定性能的场景,比如通用 DAO、规则引擎方法调度
高频场景直接生成字节码,彻底避开反射
如果某个方法调用每秒成千上万次(如 DTO 转换、日志参数提取),再怎么优化反射仍是妥协。此时应考虑编译期或加载期生成真实字节码。
- MapStruct、Lombok @Delegate:编译时生成 setter/getter 调用代码,运行时零反射
- ByteBuddy、ASM:在类加载阶段注入访问器,对外暴露纯 Java 方法接口
- ReflectASM:运行时生成代理类,用整数索引代替字符串方法名,快到接近直接调用(注意不支持桥接方法)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











