Java Reference
In-Depth Information
The lookup object, or method handles derived from it, can be returned to other
contexts, including ones where access to the method would no longer be possible.
Under those circumstances, the handle is still executable—access control is checked
at lookup time, as we can see in this example:
public
class
SneakyLoader
extends
ClassLoader
{
public
SneakyLoader
()
{
super
(
SneakyLoader
.
class
.
getClassLoader
());
}
public
Lookup
getLookup
()
{
return
MethodHandles
.
lookup
();
}
}
SneakyLoader
snLdr
=
new
SneakyLoader
();
l
=
snLdr
.
getLookup
();
lookupDefineClass
(
l
);
With a
Lookup
object, we're able to produce method handles to any method we have
access to. We can also produce a way of accessing fields that may not have a method
that gives access. The
findGetter()
and
findSetter()
methods on
Lookup
pro‐
duce method handles that can read or update fields as needed.
Invoking Method Handles
A method handle represents the ability to call a method. They are strongly typed
and as typesafe as possible. Instances are all of some subclass of
java.lang.invoke.MethodHandle
, which is a class that needs special treatment
from the JVM.
There are two ways to invoke a method handle—
invoke()
and
invokeExact()
.
Both of these take the receiver and call arguments as parameters.
invokeExact()
tries to call the method handle directly as is, whereas
invoke()
will massage call
arguments if needed.
In general,
invoke()
performs an
asType()
conversion if necessary—this converts
arguments according to these rules:
• A primitive argument will be boxed if required.
• A boxed primitive will be unboxed if required.
• Primitives will be widened is necessary.
• A
void
return type will be massaged to 0 or
null
, depending on whether the
expected return was primitive or of reference type.
•
null
values are passed through, regardless of static type.
With these potential conversions in place, invocation looks like this: