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

  • MethodHandle can be inlined by JIT; reflection cannot.
  • invokeExact is faster but requires exact types.
  • Use MethodHandle for 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 MethodHandle over reflection for repeated calls.
  • Use invokeExact for performance-critical code.
  • Cache MethodHandle instances (lookup is expensive).
  • Combine with LambdaMetafactory for dynamic lambda generation.