37.1 Method Handles And Invoke
Use MethodHandle for type-safe, high-performance dynamic invocation with better JVM optimization than reflection.
Creating a MethodHandle
import java.lang.invoke.*;
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(String.class, int.class);
MethodHandle mh = lookup.findVirtual(MyClass.class, "format", mt);
Invoking Methods
MyClass obj = new MyClass();
String result = (String) mh.invoke(obj, 42);
Or exact invocation (no boxing/unboxing):
String result = (String) mh.invokeExact(obj, 42);
Static Methods
MethodHandle mh = lookup.findStatic(Math.class, "sqrt", MethodType.methodType(double.class, double.class));
double sqrt = (double) mh.invoke(16.0);
Constructor Handles
MethodHandle ctor = lookup.findConstructor(ArrayList.class, MethodType.methodType(void.class));
ArrayList<?> list = (ArrayList<?>) ctor.invoke();
Binding and Adapters
// Bind first argument
MethodHandle bound = mh.bindTo(obj);
String res = (String) bound.invoke(42);
// Insert arguments
MethodHandle adapted = MethodHandles.insertArguments(mh, 1, 100);
Performance
MethodHandlecan be inlined by JIT; reflection cannot.invokeExactis faster but requires exact types.- Use
MethodHandlefor framework-level dispatch (e.g., serialization, ORMs).
Private Access
MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(TargetClass.class, lookup);
MethodHandle mh = privateLookup.findGetter(TargetClass.class, "privateField", String.class);
Requires module opens or --add-opens.
Guidance
- Prefer
MethodHandleover reflection for repeated calls. - Use
invokeExactfor performance-critical code. - Cache
MethodHandleinstances (lookup is expensive). - Combine with
LambdaMetafactoryfor dynamic lambda generation.