Every method handle reports its type descriptor via the type
accessor.
This type descriptor is a MethodType
object,
whose structure is a series of classes, one of which is
the return type of the method (or void.class
if none).
A method handle's type controls the types of invocations it accepts, and the kinds of transformations that apply to it.
A method handle contains a pair of special invoker methods
called invokeExact
and invoke
.
Both invoker methods provide direct access to the method handle's
underlying method, constructor, field, or other operation,
as modified by transformations of arguments and return values.
Both invokers accept calls which exactly match the method handle's own type.
The plain, inexact invoker also accepts a range of other call types.
Method handles are immutable and have no visible state. Of course, they can be bound to underlying methods or data which exhibit state. With respect to the Java Memory Model, any method handle will behave as if all of its (internal) fields are final variables. This means that any method handle made visible to the application will always be fully formed. This is true even if the method handle is published through a shared variable in a data race.
Method handles cannot be subclassed by the user.
Implementations may (or may not) create internal subclasses of MethodHandle
which may be visible via the Object.
operation. The programmer should not draw conclusions about a method handle
from its specific class, as the method handle class hierarchy (if any)
may change from time to time or across implementations from different vendors.
invokeExact
or invoke
can invoke a method handle from Java source code.
From the viewpoint of source code, these methods can take any arguments
and their result can be cast to any return type.
Formally this is accomplished by giving the invoker methods
Object
return types and variable arity Object
arguments,
but they have an additional quality called signature polymorphism
which connects this freedom of invocation directly to the JVM execution stack.
As is usual with virtual methods, source-level calls to invokeExact
and invoke
compile to an invokevirtual
instruction.
More unusually, the compiler must record the actual argument types,
and may not perform method invocation conversions on the arguments.
Instead, it must generate instructions that push them on the stack according
to their own unconverted types. The method handle object itself is pushed on
the stack before the arguments.
The compiler then generates an invokevirtual
instruction that invokes
the method handle with a symbolic type descriptor which describes the argument
and return types.
To issue a complete symbolic type descriptor, the compiler must also determine
the return type. This is based on a cast on the method invocation expression,
if there is one, or else Object
if the invocation is an expression,
or else void
if the invocation is a statement.
The cast may be to a primitive type (but not void
).
As a corner case, an uncasted null
argument is given
a symbolic type descriptor of java.lang.Void
.
The ambiguity with the type Void
is harmless, since there are no references of type
Void
except the null reference.
invokevirtual
instruction is executed
it is linked by symbolically resolving the names in the instruction
and verifying that the method call is statically legal.
This also holds for calls to invokeExact
and invoke
.
In this case, the symbolic type descriptor emitted by the compiler is checked for
correct syntax, and names it contains are resolved.
Thus, an invokevirtual
instruction which invokes
a method handle will always link, as long
as the symbolic type descriptor is syntactically well-formed
and the types exist.
When the invokevirtual
is executed after linking,
the receiving method handle's type is first checked by the JVM
to ensure that it matches the symbolic type descriptor.
If the type match fails, it means that the method which the
caller is invoking is not present on the individual
method handle being invoked.
In the case of invokeExact
, the type descriptor of the invocation
(after resolving symbolic type names) must exactly match the method type
of the receiving method handle.
In the case of plain, inexact invoke
, the resolved type descriptor
must be a valid argument to the receiver's asType
method.
Thus, plain invoke
is more permissive than invokeExact
.
After type matching, a call to invokeExact
directly
and immediately invoke the method handle's underlying method
(or other behavior, as the case may be).
A call to plain invoke
works the same as a call to
invokeExact
, if the symbolic type descriptor specified by the caller
exactly matches the method handle's own type.
If there is a type mismatch, invoke
attempts
to adjust the type of the receiving method handle,
as if by a call to asType
,
to obtain an exactly invokable method handle M2
.
This allows a more powerful negotiation of method type
between caller and callee.
Note
The adjusted method handle M2
is not directly observable,
and implementations are therefore not required to materialize it.
WrongMethodTypeException
,
either directly (in the case of invokeExact
) or indirectly as if
by a failed call to asType
(in the case of invoke
).
Thus, a method type mismatch which might show up as a linkage error
in a statically typed program can show up as
a dynamic WrongMethodTypeException
in a program which uses method handles.
Because method types contain "live" Class
objects,
method type matching takes into account both type names and class loaders.
Thus, even if a method handle M
is created in one
class loader L1
and used in another L2
,
method handle calls are type-safe, because the caller's symbolic type
descriptor, as resolved in L2
,
is matched against the original callee method's symbolic type descriptor,
as resolved in L1
.
The resolution in L1
happens when M
is created
and its type is assigned, while the resolution in L2
happens
when the invokevirtual
instruction is linked.
Apart from type descriptor checks, a method handle's capability to call its underlying method is unrestricted. If a method handle is formed on a non-public method by a class that has access to that method, the resulting handle can be used in any place by any caller who receives a reference to it.
Unlike with the Core Reflection API, where access is checked every time
a reflective method is invoked,
method handle access checking is performed
when the method handle is created.
In the case of ldc
(see below), access checking is performed as part of linking
the constant pool entry underlying the constant method handle.
Thus, handles to non-public methods, or to methods in non-public classes, should generally be kept secret. They should not be passed to untrusted code unless their use from the untrusted code would be harmless.
MethodHandles.Lookup
.
For example, a static method handle can be obtained
from Lookup.findStatic
.
There are also conversion methods from Core Reflection API objects,
such as Lookup.unreflect
.
Like classes and strings, method handles that correspond to accessible
fields, methods, and constructors can also be represented directly
in a class file's constant pool as constants to be loaded by ldc
bytecodes.
A new type of constant pool entry, CONSTANT_MethodHandle
,
refers directly to an associated CONSTANT_Methodref
,
CONSTANT_InterfaceMethodref
, or CONSTANT_Fieldref
constant pool entry.
(For full details on method handle constants, see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine
Specification.)
Method handles produced by lookups or constant loads from methods or
constructors with the variable arity modifier bit (0x0080
)
have a corresponding variable arity, as if they were defined with
the help of asVarargsCollector
or withVarargs
.
A method reference may refer either to a static or non-static method.
In the non-static case, the method handle type includes an explicit
receiver argument, prepended before any other arguments.
In the method handle's type, the initial receiver argument is typed
according to the class under which the method was initially requested.
(E.g., if a non-static method handle is obtained via ldc
,
the type of the receiver is the class named in the constant pool entry.)
Method handle constants are subject to the same link-time access checks
their corresponding bytecode instructions, and the ldc
instruction
will throw corresponding linkage errors if the bytecode behaviors would
throw such errors.
As a corollary of this, access to protected members is restricted to receivers only of the accessing class, or one of its subclasses, and the accessing class must in turn be a subclass (or package sibling) of the protected member's defining class. If a method reference refers to a protected non-static method or field of a class outside the current package, the receiver argument will be narrowed to the type of the accessing class.
When a method handle to a virtual method is invoked, the method is always looked up in the receiver (that is, the first argument).
A non-virtual method handle to a specific virtual method implementation
can also be created. These do not perform virtual lookup based on
receiver type. Such a method handle simulates the effect of
an invokespecial
instruction to the same method.
A non-virtual method handle can also be created to simulate the effect
of an invokevirtual
or invokeinterface
instruction on
a private method (as applicable).
Object x, y; String s; int i; MethodType mt; MethodHandle mh; MethodHandles.Lookup lookup = MethodHandles.lookup(); // mt is (char,char)String mt = MethodType.methodType(String.class, char.class, char.class); mh = lookup.findVirtual(String.class, "replace", mt); s = (String) mh.invokeExact("daddy",'d','n'); // invokeExact(Ljava/lang/String;CC)Ljava/lang/String; assertEquals(s, "nanny"); // weakly typed invocation (using MHs.invoke) s = (String) mh.invokeWithArguments("sappy", 'p', 'v'); assertEquals(s, "savvy"); // mt is (Object[])List mt = MethodType.methodType(java.util.List.class, Object[].class); mh = lookup.findStatic(java.util.Arrays.class, "asList", mt); assert(mh.isVarargsCollector()); x = mh.invoke("one", "two"); // invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; assertEquals(x, java.util.Arrays.asList("one","two")); // mt is (Object,Object,Object)Object mt = MethodType.genericMethodType(3); mh = mh.asType(mt); x = mh.invokeExact((Object)1, (Object)2, (Object)3); // invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; assertEquals(x, java.util.Arrays.asList(1,2,3)); // mt is ()int mt = MethodType.methodType(int.class); mh = lookup.findVirtual(java.util.List.class, "size", mt); i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3)); // invokeExact(Ljava/util/List;)I assert(i == 3); mt = MethodType.methodType(void.class, String.class); mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt); mh.invokeExact(System.out, "Hello, world."); // invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
invokeExact
or plain invoke
generates a single invokevirtual instruction with
the symbolic type descriptor indicated in the following comment.
In these examples, the helper method assertEquals
is assumed to
be a method which calls Objects.equals
on its arguments, and asserts that the result is true.
invokeExact
and invoke
are declared
to throw Throwable
,
which is to say that there is no static restriction on what a method handle
can throw. Since the JVM does not distinguish between checked
and unchecked exceptions (other than by their class, of course),
there is no particular effect on bytecode shape from ascribing
checked exceptions to method handle invocations. But in Java source
code, methods which perform method handle calls must either explicitly
throw Throwable
, or else must catch all
throwables locally, rethrowing only those which are legal in the context,
and wrapping ones which are illegal.
invokeExact
and plain invoke
is referenced by the term signature polymorphism.
As defined in the Java Language Specification,
a signature polymorphic method is one which can operate with
any of a wide range of call signatures and return types.
In source code, a call to a signature polymorphic method will
compile, regardless of the requested symbolic type descriptor.
As usual, the Java compiler emits an invokevirtual
instruction with the given symbolic type descriptor against the named method.
The unusual part is that the symbolic type descriptor is derived from
the actual argument and return types, not from the method declaration.
When the JVM processes bytecode containing signature polymorphic calls, it will successfully link any such call, regardless of its symbolic type descriptor. (In order to retain type safety, the JVM will guard such calls with suitable dynamic type checks, as described elsewhere.)
Bytecode generators, including the compiler back end, are required to emit untransformed symbolic type descriptors for these methods. Tools which determine symbolic linkage are required to accept such untransformed descriptors, without reporting linkage errors.
Lookup
API,
any class member represented by a Core Reflection API object
can be converted to a behaviorally equivalent method handle.
For example, a reflective Method
can
be converted to a method handle using
Lookup.unreflect
.
The resulting method handles generally provide more direct and efficient
access to the underlying class members.
As a special case,
when the Core Reflection API is used to view the signature polymorphic
methods invokeExact
or plain invoke
in this class,
they appear as ordinary non-polymorphic methods.
Their reflective appearance, as viewed by
Class.
,
is unaffected by their special status in this API.
For example, Method.
will report exactly those modifier bits required for any similarly
declared method, including in this case native
and varargs
bits.
As with any reflected method, these methods (when reflected) may be
invoked via java.
.
However, such reflective calls do not result in method handle invocations.
Such a call, if passed the required argument
(a single one, of type Object[]
), will ignore the argument and
will throw an UnsupportedOperationException
.
Since invokevirtual
instructions can natively
invoke method handles under any symbolic type descriptor, this reflective view conflicts
with the normal presentation of these methods via bytecodes.
Thus, these two native methods, when reflectively viewed by
Class.getDeclaredMethod
, may be regarded as placeholders only.
In order to obtain an invoker method for a particular type descriptor,
use MethodHandles.
,
or MethodHandles.
.
The Lookup.
API is also able to return a method handle
to call invokeExact
or plain invoke
,
for any specified type descriptor .
invokevirtual
instruction.
Method handles do not represent their function-like types in terms of Java parameterized (generic) types, because there are three mismatches between function-like types and parameterized Java types.
long
or double
argument counts (for purposes of arity limits) as two argument slots.
invoke
method (or other signature-polymorphic method) is non-virtual,
it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
IllegalArgumentException
.
In particular, a method handle’s type must not have an arity of the exact maximum 255.
MethodType
, MethodHandles
Modifier and Type | Class and Description |
---|---|
pack-priv static @interface | MethodHandle.
Internal marker interface which distinguishes (to the Java compiler) those methods which are signature polymorphic. |
Modifier and Type | Field and Description |
---|---|
private MethodHandle | |
private SoftReference | |
private byte | |
pack-priv final LambdaForm | |
private static final long | |
private final MethodType | |
private static final long | |
private volatile boolean |
Access | Constructor and Description |
---|---|
pack-priv | MethodHandle(MethodType type, LambdaForm form)
Package-private constructor for the method handle implementation hierarchy. |
Modifier and Type | Method and Description |
---|---|
public MethodHandle | Returns: a new method handle which collects some trailing argument into an array, before calling the original method handleoften arrayType, int Object[] , the type of the array argument which will collect the argumentsthe number of arguments to collect into a new array argument arrayLength)Makes an array-collecting method handle, which accepts a given number of trailing positional arguments and collects them into an array argument. |
public MethodHandle | Returns: a new method handle which collects some arguments into an array, before calling the original method handlethe zero-based position in the parameter list at which to start collecting. collectArgPos, Class<?> often arrayType, int Object[] , the type of the array argument which will collect the argumentsthe number of arguments to collect into a new array argument arrayLength)Makes an array-collecting method handle, which accepts a given number of positional arguments starting at a given position, and collects them into an array argument. |
pack-priv boolean | asCollectorChecks(Class<?> arrayType, int pos, int arrayLength)
See if |
public MethodHandle | Returns: a new method handle which accepts only a fixed number of argumentsMakes a fixed arity method handle which is otherwise equivalent to the current method handle. |
public MethodHandle | Returns: a new method handle which spreads its final array argument, before calling the original method handleusually arrayType, int Object[] , the type of the array argument from which to extract the spread argumentsthe number of arguments to spread from an incoming array argument arrayLength)Makes an array-spreading method handle, which accepts a trailing array argument and spreads its elements as positional arguments. |
public MethodHandle | Returns: a new method handle which spreads an array argument at a given position, before calling the original method handlethe position (zero-based index) in the argument list at which spreading should start. spreadArgPos, Class<?> usually arrayType, int Object[] , the type of the array argument from which to extract the spread argumentsthe number of arguments to spread from an incoming array argument arrayLength)Makes an array-spreading method handle, which accepts an array argument at a given position and spreads its elements as positional arguments in place of the array. |
private MethodType | asSpreaderChecks(Class<?> arrayType, int pos, int arrayLength)
See if |
public final MethodHandle | Returns: a method handle which delegates tothis after performing
any necessary argument conversions, and arranges for any
necessary return value conversionsthe expected type of the new method handle newType)Produces an adapter method handle which adapts the type of the current method handle to a new type. |
private MethodHandle | |
pack-priv MethodHandle | |
public MethodHandle | Returns: a new method handle which can collect any number of trailing arguments into an array, before calling the original method handleoften arrayType)Object[] , the type of the array argument which will collect the argumentsMakes a variable arity adapter which is able to accept any number of trailing positional arguments and collect them into an array argument. |
pack-priv BoundMethodHandle | |
public MethodHandle | |
pack-priv abstract MethodHandle | |
pack-priv void | |
pack-priv static String | debugPrefix(int indentLevel)
Various debugging methods in MethodHandle (and subclasses thereof) and LambdaForm
take an `indentLevel` argument, so that |
pack-priv String | debugString(int
If negative, return only information about this MethodHandle.
Otherwise, return information about this MethodHandle and (recursively) all other
MethodHandles, if any, that are invoked directly or indirectly by this MethodHandle.
During the recursion, `indentLevel` is incremented (see
BoundMethodHandle.internalValues()) to improve readability of
the nested structure. indentLevel)Return a string with a several lines describing the method handle structure. |
pack-priv String | |
public Optional | describeConstable()
Implements java. Return a nominal descriptor for this instance, if one can be
constructed, or an empty |
private static ClassLoader | getApproximateCommonClassLoader(MethodType mt)
Tries to find the most specific |
pack-priv Class | |
pack-priv LambdaForm | |
pack-priv MemberName | |
pack-priv Object | |
pack-priv Object | |
pack-priv Object | |
pack-priv Object | |
pack-priv MethodHandleImpl. | |
public final native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Invokes the method handle, allowing any caller type descriptor, and optionally performing conversions on arguments and return values. |
pack-priv final native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Private method for trusted invocation of a method handle respecting simplified signatures. |
public final native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match. |
public Object | Returns: the result returned by the targetthe arguments to pass to the target arguments)Performs a variable arity invocation, passing the arguments in the given array
to the method handle, as if via an inexact |
public Object | Returns: the result returned by the targetthe arguments to pass to the target arguments)Performs a variable arity invocation, passing the arguments in the given list
to the method handle, as if via an inexact |
private static boolean | |
private static boolean | |
pack-priv boolean | |
pack-priv boolean | |
private boolean | isSafeToCache(MethodType newType)
Returns true if |
public boolean | Returns: true if this method handle accepts more than one arity of plain, inexactinvoke callsDetermines if this method handle supports variable arity calls. |
private static boolean | |
private static boolean | |
pack-priv static native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Private method for trusted invocation of a MemberName of kind |
pack-priv static native Object | |
pack-priv static native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Private method for trusted invocation of a MemberName of kind |
pack-priv static native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Private method for trusted invocation of a MemberName of kind |
pack-priv static native Object | Returns: the signature-polymorphic result, statically represented usingObject the signature-polymorphic parameter list, statically represented using varargs args)Private method for trusted invocation of a MemberName of kind |
pack-priv void | |
pack-priv abstract BoundMethodHandle | Returns: a behaviorally equivalent BMHRequire this method handle to be a BMH, or else replace it with a "wrapper" BMH. |
private MethodHandle | |
pack-priv MethodHandle | |
private void | |
pack-priv String | |
public String | Returns: a string representation of the method handleOverrides java. Returns a string representation of the method handle,
starting with the string |
public MethodType | |
pack-priv void | updateForm(Function<LambdaForm, LambdaForm> updater)
Replace the old lambda form of this method handle with a new one. |
pack-priv MethodHandle | |
pack-priv boolean | |
pack-priv MethodHandle | |
public MethodHandle | Returns: a method handle of the same type, with possibly adjusted variable arity behaviortrue if the return method handle should have variable arity behavior makeVarargs)Adapts this method handle to be variable arity if the boolean flag is true, else fixed arity. |