MethodHandle 高性能依赖初始化阶段缓存句柄与精确类型匹配,避免运行时查找和装箱;高频场景用 static final 字段或 ConcurrentHashMap 缓存,调用仅用 invokeExact,字段访问优先选 VarHandle。

MethodHandle 不是反射的“升级版 API”,而是把开销从每次调用压到初始化阶段,靠 JVM 对稳定句柄的深度内联和去虚拟化,实现接近直接调用的性能。它快的前提不是写法新,而是用得对。
缓存句柄,绝不重复查找
每次调用 Lookup.findVirtual() 或 findGetter() 都会触发符号解析、权限检查、签名验证,开销远超 Method.invoke()。这一步必须只做一次。
- 高频固定方法(如 ORM 的
setId):声明为static final MethodHandle字段,在类加载时初始化 - 动态场景(如泛型 JSON 反序列化):用
ConcurrentHashMap<Key, MethodHandle>缓存,key 可由Class<?> + 字段名 + 字段类型组成 - 别在循环、setter、消息分发热路径里 new Lookup 或反复调用 findXXX
只用 invokeExact,禁用 invoke 和 invokeWithArguments
invokeExact() 要求参数与返回值类型和句柄的 MethodType 完全一致——int.class 就不能传 Integer,String.class 就不能传 Object。不匹配直接抛 WrongMethodTypeException,但换来零装箱、零数组分配、JIT 可内联。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 调试时先打印
handle.type(),和你传的实参类型逐个比对 - 需要适配?用
asType()在初始化阶段一次性转换并缓存,别在每次调用前转 - 避免在循环里反复
asType,那会生成新句柄,破坏内联机会
构造时指定精确类型,避开包装类和泛型陷阱
基本类型字段必须用 int.class、long.class 等原始类型;调用 public String getName(),MethodType 必须写成 methodType(String.class),不能用 Object.class。
立即学习“Java免费学习笔记(深入)”;
- 读取
int id字段,用findGetter(User.class, "id", int.class),而非Integer.class—— 后者触发自动装箱,性能掉回反射水平 - 私有成员访问不用
setAccessible(true),改用MethodHandles.privateLookupIn(Owner.class, lookup),且 JDK 9+ 需确保目标模块opens包 - 静态方法用
findStatic,构造器用findConstructor,选错会抛NoSuchMethodException
字段访问优先用 VarHandle
如果只是读写 public 或普通实例字段,VarHandle 比 MethodHandle 更轻:无对象分配、无异常路径、无 invoke 开销,实测快 10–20%,还天然支持 compareAndSet、getAndAdd 等原子操作。
- 同样建议
static final缓存:private static final VarHandle ID_HANDLE = MethodHandles.lookup().findVarHandle(User.class, "id", int.class); - 字段类型必须与声明类型严格一致,否则触发隐式转换,性能退化
- 适合高并发计数、状态切换等场景,无需额外
synchronized或Lock


















