skip to content

What is a MethodHandle in java.lang.invoke, and how do you obtain one via MethodHandles.lookup()?

level: middleimportance: should knowfreq 45%

answer

  1. Typed function pointer to a method/ctor/field
  2. Lookup = factory + access context
  3. findVirtual/findStatic/findConstructor
  4. MethodType = signature, no name
  5. Access checked at lookup, not invoke

basics

~20 s

A MethodHandle is a typed, directly-callable reference to a method, constructor, or field. You first get a Lookup object from MethodHandles.lookup(), then ask it to find the method (e.g. findVirtual) and get back a handle you can invoke.

solid answer

~40 s

A MethodHandle (java.lang.invoke) is a strongly-typed, low-level reference to an executable member - a method, constructor, or field accessor - that you can invoke directly. To create one you first obtain a Lookup, normally via MethodHandles.lookup(), which is a factory carrying the access rights of the calling class. You then call a finder such as findVirtual, findStatic, findConstructor, findGetter or findSetter, passing the owning class, the member name, and a MethodType describing the signature. The Lookup performs the access check at lookup time (so invocation is fast and unchecked), and returns a MethodHandle whose type() matches that signature. Compared with java.lang.reflect.Method, handles are immutable, type-aware, and the JIT can optimise them aggressively, making them the modern foundation for invokedynamic, lambdas, string concatenation, and var-args adaptation.

go deeper

for a junior

Can state that a MethodHandle is a typed reference to a method and that you get one through MethodHandles.lookup() then a find* call.

for a middle

Knows the finder methods (findVirtual/findStatic/findConstructor), that MethodType describes the signature, and that the receiver becomes a leading arg for virtual handles.

for a senior

Explains that Lookup carries access context, that the access check happens at lookup time enabling cheap invocation, and contrasts it with reflective Method.

for a principal

Frames MethodHandles as the invokedynamic substrate underlying lambdas/string-concat and reasons about when to build dynamic call sites versus codegen.

### The problem MethodHandles solve Before Java 7, the only way to call a method whose identity you only knew at runtime was the **Reflection API** (`java.lang.reflect.Method`). Reflection works but has drawbacks: every `invoke` call re-checks access permissions, arguments are boxed into an `Object[]`, and the JIT (the just-in-time compiler that turns bytecode into machine code) struggles to optimise through it. `java.lang.invoke.MethodHandle`, introduced in Java 7, is the modern, faster alternative. Think of a **MethodHandle as a typed function pointer**: an immutable object that points at one executable member (a method, a constructor, or a field getter/setter) and knows the exact signature of what it points at. ### Key terms, defined - **`MethodHandle`** - the callable reference itself. It has a `type()` of class `MethodType`. - **`MethodType`** - an immutable description of a signature: the return type plus the parameter types, with **no method name**. E.g. `(int,int)->int` is a MethodType. You build one with `MethodType.methodType(returnType, paramTypes...)`. - **`MethodHandles.Lookup`** - a *factory* object that also carries an **access context**: it remembers which class requested it, and therefore what that class is allowed to see (public, private, package members visible from the lookup class). You usually get it by calling `MethodHandles.lookup()` from inside the class that needs the access. - **`MethodHandles`** (plural, the utility class) - holds static factory and combinator methods (`lookup()`, `publicLookup()`, `privateLookupIn(...)`, adapters like `insertArguments`, etc.). ### How you obtain a handle, step by step ```java // 1. Get a Lookup carrying THIS class's access rights MethodHandles.Lookup lookup = MethodHandles.lookup(); // 2. Describe the signature you want (return type first) MethodType mt = MethodType.methodType(String.class, int.class); // String f(int) // 3. Ask the lookup to find the member; access is checked HERE MethodHandle mh = lookup.findVirtual(Integer.class, "toString", MethodType.methodType(String.class)); ``` The finder method you call depends on the kind of member: - `findVirtual(refc, name, type)` - an instance (overridable) method; the receiver becomes a *leading* argument. - `findStatic(refc, name, type)` - a static method. - `findConstructor(refc, type)` - a constructor; the return type of `type` must be `void`, the handle returns a new instance. - `findGetter`/`findSetter` - read/write an instance field; `findStaticGetter`/`findStaticSetter` for static fields. - `findSpecial` - non-virtual (super) invocation. ### The crucial idea: access is checked at lookup time When `findVirtual` returns successfully, the permission check is **already done**. The resulting handle can then be invoked any number of times with no further access checks - this is part of why it is fast. A reflective `Method`, by contrast, can re-check (unless you call `setAccessible(true)`). ### Why use it instead of reflection? 1. **Performance** - the JIT treats a constant MethodHandle almost like a direct call; invocation avoids per-call access checks and (with `invokeExact`) avoids boxing. 2. **Type safety** - the handle knows its `MethodType`; signature mismatches fail loudly. 3. **Composability** - handles can be transformed (bind arguments, change types, filter, fold) into new handles. 4. **It is the runtime substrate for `invokedynamic`** - lambdas, method references, and `String` concatenation all bootstrap through MethodHandles. A junior should know it is "a fast, typed alternative to a reflective Method". A senior should know lookup carries access context and the check happens at lookup time. A principal should reach for it when building dynamic dispatch, bytecode-light frameworks, or `invokedynamic` call sites.

  • What does the receiver object map to for a handle from findVirtual?
    It becomes the first (leading) parameter of the handle's MethodType, so you pass the instance as the first argument when invoking.
  • What is the difference between MethodHandles.lookup() and MethodHandles.publicLookup()?
    lookup() captures the calling class's full access (including its private/package members); publicLookup() can only resolve public members of exported packages and has no privileged context.

saying these in an interview costs you the question

  • Saying MethodType includes the method name (it does not - just return + params)
  • Claiming access is re-checked on every invoke (it is checked once, at lookup)
  • Confusing MethodHandle (the callable) with MethodHandles (the utility class)
  • Thinking lookup() returns something global - it carries the caller's access rights

context