MethodHandle 比 Method.invoke() 更快,因其将权限检查、类型校验、参数包装等开销移至句柄创建阶段,调用时仅剩精准匹配与直接跳转;invokeExact() 无装箱、无数组封装、无异常包装,且 JIT 可内联优化,但需缓存句柄并严格匹配类型。

MethodHandle 比 Method.invoke() 更快,不是因为它“更底层”,而是 JVM 对它的调用路径做了根本性优化:把开销大的操作(权限检查、类型校验、参数包装)全部移到句柄创建阶段,调用时只剩一次精准匹配和直接跳转。
权限检查只做一次,不再每次拦路
反射每次调用 Method.invoke() 都会重新执行 AccessibleObject.checkAccess(),哪怕已调用 setAccessible(true),JVM 也不会缓存该结果。SecurityManager 检查、模块访问验证、私有成员绕过逻辑全在运行时重跑。
MethodHandle 在 Lookup.findVirtual() 等查找方法返回句柄前,就完成全部权限判定。成功后生成的句柄是“已授权”状态,后续 invokeExact() 调用完全跳过安全检查。
调用时不打包、不装箱、不异常包装
Method.invoke() 必须接收 Object[] 参数数组,导致每次调用都要: – 创建临时 Object[] 数组 – 对基本类型自动装箱(int → Integer) – 把 checked exception 包装成 InvocationTargetException – 多一层 JNI 层跳转
MethodHandle.invokeExact() 直接按 MethodType 约定签名传参:int 就传 int,String 就传 String,无数组封装、无装拆箱、无异常转换,参数直压栈,返回值直出栈。
JIT 编译器真正愿意优化它
HotSpot 对 Method.invoke() 基本不内联——它是多态、泛型擦除、反射标记三重障碍的典型慢路径。而 MethodHandle.invokeExact() 被 JIT 视为“准静态调用”:
- 句柄复用稳定时,可去虚化(devirtualize),甚至内联目标方法体
- 配合 invokedynamic 指令,首次调用后绑定调用点,后续走直接跳转
- 无锁、无临时对象,高并发下无同步竞争
性能优势有前提,不是用了就快
MethodHandle 的初始化成本高于反射:符号解析、字节码验证、句柄生成都发生在 lookup 阶段。所以:
- 不能在循环里反复调用 findVirtual() —— 查找本身很重
- 必须缓存 MethodHandle 实例(static final 或 ConcurrentHashMap)
- 必须用 invokeExact() 并确保类型完全匹配(int.class ≠ Integer.class)
- 跨模块访问私有成员,要用 privateLookupIn(),不能靠 setAccessible(true)
单次调用反而比反射慢;只有高频复用 + 类型严格 + 初始化前置,才能稳定快出 2–5 倍。










