public static final class MethodHandles.Lookup extends Object
A lookup class which needs to create method handles will call
MethodHandles.lookup
to create a factory for itself.
When the Lookup
factory object is created, the identity of the lookup class is
determined, and securely stored in the Lookup
object.
The lookup class (or its delegates) may then use factory methods
on the Lookup
object to create method handles for access-checked members.
This includes all methods, constructors, and fields which are allowed to the lookup class,
even private ones.
Lookup
object correspond to all major
use cases for methods, constructors, and fields.
Each method handle created by a factory method is the functional
equivalent of a particular bytecode behavior.
(Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
Here is a summary of the correspondence between these factory methods and
the behavior of the resulting method handles:
lookup expression | member | bytecode behavior |
---|---|---|
lookup.findGetter(C.class,"f",FT.class) |
FT f; | (T) this.f; |
lookup.findStaticGetter(C.class,"f",FT.class) |
static FT f; | (T) C.f; |
lookup.findSetter(C.class,"f",FT.class) |
FT f; | this.f = x; |
lookup.findStaticSetter(C.class,"f",FT.class) |
static FT f; | C.f = arg; |
lookup.findVirtual(C.class,"m",MT) |
T m(A*); | (T) this.m(arg*); |
lookup.findStatic(C.class,"m",MT) |
static T m(A*); | (T) C.m(arg*); |
lookup.findSpecial(C.class,"m",MT,this.class) |
T m(A*); | (T) super.m(arg*); |
lookup.findConstructor(C.class,MT) |
C(A*); | new C(arg*); |
lookup.unreflectGetter(aField) |
(static )?FT f; | (FT) aField.get(thisOrNull); |
lookup.unreflectSetter(aField) |
(static )?FT f; | aField.set(thisOrNull, arg); |
lookup.unreflect(aMethod) |
(static )?T m(A*); | (T) aMethod.invoke(thisOrNull, arg*); |
lookup.unreflectConstructor(aConstructor) |
C(A*); | (C) aConstructor.newInstance(arg*); |
lookup.unreflect(aMethod) |
(static )?T m(A*); | (T) aMethod.invoke(thisOrNull, arg*); |
lookup.findClass("C") |
class C { ... } | C.class; |
C
is the class or interface being searched for a member,
documented as a parameter named refc
in the lookup methods.
The method type MT
is composed from the return type T
and the sequence of argument types A*
.
The constructor also has a sequence of argument types A*
and
is deemed to return the newly-created object of type C
.
Both MT
and the field type FT
are documented as a parameter named type
.
The formal parameter this
stands for the self-reference of type C
;
if it is present, it is always the leading argument to the method handle invocation.
(In the case of some protected
members, this
may be
restricted in type to the lookup class; see below.)
The name arg
stands for all the other method handle arguments.
In the code examples for the Core Reflection API, the name thisOrNull
stands for a null reference if the accessed method or field is static,
and this
otherwise.
The names aMethod
, aField
, and aConstructor
stand
for reflective objects corresponding to the given members.
The bytecode behavior for a findClass
operation is a load of a constant class,
as if by ldc CONSTANT_Class
.
The behavior is represented, not as a method handle, but directly as a Class
constant.
In cases where the given member is of variable arity (i.e., a method or constructor) the returned method handle will also be of variable arity. In all other cases, the returned method handle will be of fixed arity.
Discussion: The equivalence between looked-up method handles and underlying class members and bytecode behaviors can break down in a few ways:
C
is not symbolically accessible from the lookup class's loader,
the lookup can still succeed, even when there is no equivalent
Java expression or bytecoded constant.
T
or MT
is not symbolically accessible from the lookup class's loader,
the lookup can still succeed.
For example, lookups for MethodHandle.invokeExact
and
MethodHandle.invoke
will always succeed, regardless of requested type.
ldc
instruction on a CONSTANT_MethodHandle
constant is not subject to security manager checks.
Lookup
,
when a method handle is created.
This is a key difference from the Core Reflection API, since
java.lang.reflect.Method.invoke
performs access checking against every caller, on every call.
All access checks start from a Lookup
object, which
compares its recorded lookup class against all requests to
create method handles.
A single Lookup
object can be used to create any number
of access-checked method handles, all checked against a single
lookup class.
A Lookup
object can be shared with other trusted code,
such as a metaobject protocol.
A shared Lookup
object delegates the capability
to create method handles on private members of the lookup class.
Even if privileged code uses the Lookup
object,
the access checking is confined to the privileges of the
original lookup class.
A lookup can fail, because
the containing class is not accessible to the lookup class, or
because the desired class member is missing, or because the
desired class member is not accessible to the lookup class, or
because the lookup object is not trusted enough to access the member.
In any of these cases, a ReflectiveOperationException
will be
thrown from the attempted lookup. The exact class will be one of
the following:
In general, the conditions under which a method handle may be
looked up for a method M
are no more restrictive than the conditions
under which the lookup class could have compiled, verified, and resolved a call to M
.
Where the JVM would raise exceptions like NoSuchMethodError
,
a method handle lookup will generally raise a corresponding
checked exception, such as NoSuchMethodException
.
And the effect of invoking the method handle resulting from the lookup
is exactly equivalent
to executing the compiled, verified, and resolved call to M
.
The same point is true of fields and constructors.
Discussion:
Access checks only apply to named and reflected methods,
constructors, and fields.
Other method handle creation methods, such as
MethodHandle.asType
,
do not require any access checks, and are used
independently of any Lookup
object.
If the desired member is protected
, the usual JVM rules apply,
including the requirement that the lookup class must be either be in the
same package as the desired member, or must inherit that member.
(See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
In addition, if the desired member is a non-static field or method
in a different package, the resulting method handle may only be applied
to objects of the lookup class or one of its subclasses.
This requirement is enforced by narrowing the type of the leading
this
parameter from C
(which will necessarily be a superclass of the lookup class)
to the lookup class itself.
The JVM imposes a similar requirement on invokespecial
instruction,
that the receiver argument must match both the resolved method and
the current class. Again, this requirement is enforced by narrowing the
type of the leading parameter to the resulting method handle.
(See the Java Virtual Machine Specification, section 4.10.1.9.)
The JVM represents constructors and static initializer blocks as internal methods
with special names ("<init>"
and "<clinit>"
).
The internal syntax of invocation instructions allows them to refer to such internal
methods as if they were normal methods, but the JVM bytecode verifier rejects them.
A lookup of such an internal method will produce a NoSuchMethodException
.
In some cases, access between nested classes is obtained by the Java compiler by creating
an wrapper method to access a private method of another class
in the same top-level declaration.
For example, a nested class C.D
can access private members within other related classes such as
C
, C.D.E
, or C.B
,
but the Java compiler may need to generate wrapper methods in
those related classes. In such cases, a Lookup
object on
C.E
would be unable to those private members.
A workaround for this limitation is the Lookup.in
method,
which can transform a lookup on C.E
into one on any of those other
classes, without special elevation of privilege.
The accesses permitted to a given lookup object may be limited,
according to its set of lookupModes
,
to a subset of members normally accessible to the lookup class.
For example, the publicLookup
method produces a lookup object which is only allowed to access
public members in public classes of exported packages.
The caller sensitive method lookup
produces a lookup object with full capabilities relative to
its caller class, to emulate all supported bytecode behaviors.
Also, the Lookup.in
method may produce a lookup object
with fewer access modes than the original lookup object.
Discussion of private access:
We say that a lookup has private access
if its lookup modes
include the possibility of accessing private
members.
As documented in the relevant methods elsewhere,
only lookups with private access possess the following capabilities:
Class.forName
emulate invokespecial
instructions
delegated lookup objects
which have private access to other classes
within the same package member
Each of these permissions is a consequence of the fact that a lookup object with private access can be securely traced back to an originating class, whose bytecode behaviors and Java language access permissions can be reliably determined and emulated by method handles.
Class
object is
available. Such cross-loader references are also possible with the
Core Reflection API, and are impossible to bytecode instructions
such as invokestatic
or getfield
.
There is a security manager API
to allow applications to check such cross-loader references.
These checks apply to both the MethodHandles.Lookup
API
and the Core Reflection API
(as found on Class
).
If a security manager is present, member and class lookups are subject to
additional checks.
From one to three calls are made to the security manager.
Any of these calls can refuse access by throwing a
SecurityException
.
Define smgr
as the security manager,
lookc
as the lookup class of the current lookup object,
refc
as the containing class in which the member
is being sought, and defc
as the class in which the
member is actually defined.
(If a class or other type is being accessed,
the refc
and defc
values are the class itself.)
The value lookc
is defined as not present
if the current lookup object does not have
private access.
The calls are made according to the following rules:
lookc
is not present, or if its class loader is not
the same as or an ancestor of the class loader of refc
,
then smgr.checkPackageAccess(refcPkg)
is called,
where refcPkg
is the package of refc
.
lookc
is not present, then
smgr.checkPermission
with RuntimePermission("accessDeclaredMembers")
is called.
null
class loader,
and lookc
is not present, then
smgr.checkPermission
with RuntimePermission("getClassLoader")
is called.
lookc
is not present,
and if defc
and refc
are different,
then smgr.checkPackageAccess(defcPkg)
is called,
where defcPkg
is the package of defc
.
If a method handle for a caller-sensitive method is requested, the general rules for bytecode behaviors apply, but they take account of the lookup class in a special way. The resulting method handle behaves as if it were called from an instruction contained in the lookup class, so that the caller-sensitive method detects the lookup class. (By contrast, the invoker of the method handle is disregarded.) Thus, in the case of caller-sensitive methods, different lookup classes may give rise to differently behaving method handles.
In cases where the lookup object is
publicLookup()
,
or some other lookup object without
private access,
the lookup class is disregarded.
In such cases, no caller-sensitive method handle can be created,
access is forbidden, and the lookup fails with an
IllegalAccessException
.
Discussion:
For example, the caller-sensitive method
Class.forName(x)
can return varying classes or throw varying exceptions,
depending on the class loader of the class that calls it.
A public lookup of Class.forName
will fail, because
there is no reasonable way to determine its bytecode behavior.
If an application caches method handles for broad sharing,
it should use publicLookup()
to create them.
If there is a lookup of Class.forName
, it will fail,
and the application must take appropriate action in that case.
It may be that a later lookup, perhaps during the invocation of a
bootstrap method, can incorporate the specific identity
of the caller, making the method accessible.
The function MethodHandles.lookup
is caller sensitive
so that there can be a secure foundation for lookups.
Nearly all other methods in the JSR 292 API rely on lookup
objects to check access requests.
Modifier and Type | Field | Description |
---|---|---|
static int |
MODULE |
NEW A single-bit mask representing
module access (default access),
which may contribute to the result of lookupModes . |
static int |
UNCONDITIONAL |
NEW A single-bit mask representing
unconditional access
which may contribute to the result of lookupModes . |
static int |
PACKAGE |
A single-bit mask representing
package access (default access),
which may contribute to the result of lookupModes . |
static int |
PRIVATE |
A single-bit mask representing
private access,
which may contribute to the result of lookupModes . |
static int |
PROTECTED |
A single-bit mask representing
protected access,
which may contribute to the result of lookupModes . |
static int |
PUBLIC |
A single-bit mask representing
public access,
which may contribute to the result of lookupModes . |
Modifier and Type | Method | Description |
---|---|---|
Class<?> |
defineClass(byte[] bytes) |
NEW Defines a class to the same class loader and in the same runtime package and
protection domain as this lookup's
lookup class.
|
MethodHandles.Lookup |
in(Class<?> requestedLookupClass) |
REVISED Creates a lookup on the specified new lookup class.
|
int |
lookupModes() |
REVISED Tells which access-protection classes of members this lookup object can produce.
|
String |
toString() |
REVISED Displays the name of the class from which lookups are to be made.
|
Class<?> |
accessClass(Class<?> targetClass) |
Determines if a class can be accessed from the lookup context defined by this
Lookup object. |
MethodHandle |
bind(Object receiver,
String name,
MethodType type) |
Produces an early-bound method handle for a non-static method.
|
MethodHandles.Lookup |
dropLookupMode(int modeToDrop) |
Creates a lookup on the same lookup class which this lookup object
finds members, but with a lookup mode that has lost the given lookup mode.
|
Class<?> |
findClass(String targetName) |
Looks up a class by name from the lookup context defined by this
Lookup object. |
MethodHandle |
findConstructor(Class<?> refc,
MethodType type) |
Produces a method handle which creates an object and initializes it, using
the constructor of the specified type.
|
MethodHandle |
findGetter(Class<?> refc,
String name,
Class<?> type) |
Produces a method handle giving read access to a non-static field.
|
MethodHandle |
findSetter(Class<?> refc,
String name,
Class<?> type) |
Produces a method handle giving write access to a non-static field.
|
MethodHandle |
findSpecial(Class<?> refc,
String name,
MethodType type,
Class<?> specialCaller) |
Produces an early-bound method handle for a virtual method.
|
MethodHandle |
findStatic(Class<?> refc,
String name,
MethodType type) |
Produces a method handle for a static method.
|
MethodHandle |
findStaticGetter(Class<?> refc,
String name,
Class<?> type) |
Produces a method handle giving read access to a static field.
|
MethodHandle |
findStaticSetter(Class<?> refc,
String name,
Class<?> type) |
Produces a method handle giving write access to a static field.
|
VarHandle |
findStaticVarHandle(Class<?> decl,
String name,
Class<?> type) |
Produces a VarHandle giving access to a static field
name of
type type declared in a class of type decl . |
VarHandle |
findVarHandle(Class<?> recv,
String name,
Class<?> type) |
Produces a VarHandle giving access to a non-static field
name
of type type declared in a class of type recv . |
MethodHandle |
findVirtual(Class<?> refc,
String name,
MethodType type) |
Produces a method handle for a virtual method.
|
boolean |
hasPrivateAccess() |
Returns
true if this lookup has PRIVATE access. |
Class<?> |
lookupClass() |
Tells which class is performing the lookup.
|
MethodHandleInfo |
revealDirect(MethodHandle target) |
Cracks a direct method handle
created by this lookup object or a similar one.
|
MethodHandle |
unreflect(Method m) |
Makes a direct method handle
to m, if the lookup class has permission.
|
MethodHandle |
unreflectConstructor(Constructor<?> c) |
Produces a method handle for a reflected constructor.
|
MethodHandle |
unreflectGetter(Field f) |
Produces a method handle giving read access to a reflected field.
|
MethodHandle |
unreflectSetter(Field f) |
Produces a method handle giving write access to a reflected field.
|
MethodHandle |
unreflectSpecial(Method m,
Class<?> specialCaller) |
Produces a method handle for a reflected method.
|
VarHandle |
unreflectVarHandle(Field f) |
Produces a VarHandle giving access to a reflected field
f
of type T declared in a class of type R . |
public static final int PUBLIC
public
access,
which may contribute to the result of lookupModes
.
The value, 0x01
, happens to be the same as the value of the
public
modifier bit.public static final int PRIVATE
private
access,
which may contribute to the result of lookupModes
.
The value, 0x02
, happens to be the same as the value of the
private
modifier bit.public static final int PROTECTED
protected
access,
which may contribute to the result of lookupModes
.
The value, 0x04
, happens to be the same as the value of the
protected
modifier bit.public static final int PACKAGE
package
access (default access),
which may contribute to the result of lookupModes
.
The value is 0x08
, which does not correspond meaningfully to
any particular modifier bit.public static final int MODULE
module
access (default access),
which may contribute to the result of lookupModes
.
The value is 0x10
, which does not correspond meaningfully to
any particular modifier bit.
In conjunction with the PUBLIC
modifier bit, a Lookup
with this lookup mode can access all public types in the module of the
lookup class and public types in packages exported by other modules
to the module of the lookup class.public static final int UNCONDITIONAL
unconditional
access
which may contribute to the result of lookupModes
.
The value is 0x20
, which does not correspond meaningfully to
any particular modifier bit.
A Lookup
with this lookup mode assumes readability.
In conjunction with the PUBLIC
modifier bit, a Lookup
with this lookup mode can access all public members of public types
of all modules where the type is in a package that is exported unconditionally
.MethodHandles.publicLookup()
,
Constant Field Valuespublic Class<?> lookupClass()
The class implies a maximum level of access permission,
but the permissions may be additionally limited by the bitmask
lookupModes
, which controls whether non-public members
can be accessed.
public int lookupModes()
A freshly-created lookup object
on the caller's class has
all possible bits set, except UNCONDITIONAL
. The lookup can be used to
access all members of the caller's class, all public types in the caller's module,
and all public types in packages exported by other modules to the caller's module.
A lookup object on a new lookup class
created from a previous lookup object
may have some mode bits set to zero.
Mode bits can also be
directly cleared.
Once cleared, mode bits cannot be restored from the downgraded lookup object.
The purpose of this is to restrict access via the new lookup object,
so that it can access only names which can be reached by the original
lookup object, and also by the new lookup class.
in(java.lang.Class<?>)
,
dropLookupMode(int)
public MethodHandles.Lookup in(Class<?> requestedLookupClass)
lookupClass
.
However, the resulting Lookup
object is guaranteed
to have no more access capabilities than the original.
In particular, access capabilities can be lost as follows:
named
module, and
the new lookup class is in a different module M
, then no members, not
even public members in M
's exported packages, will be accessible.
The exception to this is when this lookup is publicLookup
, in which case PUBLIC
access is not lost.
MODULE
access is lost.
UNCONDITIONAL
is lost.
The resulting lookup's capabilities for loading classes
(used during findClass(java.lang.String)
invocations)
are determined by the lookup class' loader,
which may change due to this operation.
requestedLookupClass
- the desired lookup class for the new lookup objectNullPointerException
- if the argument is nullpublic MethodHandles.Lookup dropLookupMode(int modeToDrop)
PUBLIC
, MODULE
, PACKAGE
, PROTECTED
or PRIVATE
.
PROTECTED
and UNCONDITIONAL
are always
dropped and so the resulting lookup mode will never have these access capabilities.
When dropping PACKAGE
then the resulting lookup will not have PACKAGE
or PRIVATE
access. When dropping MODULE
then the resulting lookup will
not have MODULE
, PACKAGE
, or PRIVATE
access. If PUBLIC
is dropped then the resulting lookup has no access.modeToDrop
- the lookup mode to dropIllegalArgumentException
- if modeToDrop
is not one of PUBLIC
,
MODULE
, PACKAGE
, PROTECTED
, PRIVATE
or UNCONDITIONAL
MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)
public Class<?> defineClass(byte[] bytes) throws IllegalAccessException
The lookup modes for this lookup must include
PACKAGE
access as default (package) members will be
accessible to the class. The PACKAGE
lookup mode serves to authenticate
that the lookup object was created by a caller in the runtime package (or derived
from a lookup originally created by suitably privileged code to a target class in
the runtime package).
The bytes
parameter is the class bytes of a valid class file (as defined
by the The Java Virtual Machine Specification) with a class name in the
same package as the lookup class.
This method does not run the class initializer. The class initializer may run at a later time, as detailed in section 12.4 of the The Java Language Specification.
If there is a security manager, its checkPermission
method is first called
to check RuntimePermission("defineClass")
.
bytes
- the class bytesClass
object for the classIllegalArgumentException
- the bytes are for a class in a different package
to the lookup classIllegalAccessException
- if this lookup does not have PACKAGE
accessLinkageError
- if the class is malformed (ClassFormatError
), cannot be
verified (VerifyError
), is already defined, or another linkage error occursSecurityException
- if denied by the security managerNullPointerException
- if bytes
is null
MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)
,
dropLookupMode(int)
,
ClassLoader.defineClass(String,byte[],int,int,ProtectionDomain)
public String toString()
Class.getName
.)
If there are restrictions on the access permitted to this lookup,
this is indicated by adding a suffix to the class name, consisting
of a slash and a keyword. The keyword represents the strongest
allowed access, and is chosen as follows:
MethodHandles.lookup
.
Objects created by Lookup.in
always have restricted access, and will display a suffix.
(It may seem strange that protected access should be stronger than private access. Viewed independently from package access, protected access is the first to be lost, because it requires a direct subclass relationship between caller and callee.)
toString
in class Object
in(java.lang.Class<?>)
public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
findVirtual
or findSpecial
.)
The method and all its argument types must be accessible to the lookup object.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set.
If the returned method handle is invoked, the method's class will be initialized, if it has not already been initialized.
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_asList = publicLookup().findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
refc
- the class from which the method is accessedname
- the name of the methodtype
- the type of the methodNoSuchMethodException
- if the method does not existIllegalAccessException
- if access checking fails,
or if the method is not static
,
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsSecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
refc
) prepended.
The method and all its argument types must be accessible to the lookup object.
When called, the handle will treat the first argument as a receiver
and dispatch on the receiver's type to determine which method
implementation to enter.
(The dispatching action is identical with that performed by an
invokevirtual
or invokeinterface
instruction.)
The first argument will be of type refc
if the lookup
class has full privileges to access the member. Otherwise
the member must be protected
and the first argument
will be restricted in type to the lookup class.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set.
Because of the general equivalence between invokevirtual
instructions and method handles produced by findVirtual
,
if the class is MethodHandle
and the name string is
invokeExact
or invoke
, the resulting
method handle is equivalent to one produced by
MethodHandles.exactInvoker
or
MethodHandles.invoker
with the same type
argument.
If the class is VarHandle
and the name string corresponds to
the name of a signature-polymorphic access mode method, the resulting
method handle is equivalent to one produced by
MethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType)
with
the access mode corresponding to the name string and with the same
type
arguments.
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_concat = publicLookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class, "hashCode", methodType(int.class)); MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class, "hashCode", methodType(int.class)); assertEquals("xy", (String) MH_concat.invokeExact("x", "y")); assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy")); assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy")); // interface method: MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class, "subSequence", methodType(CharSequence.class, int.class, int.class)); assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString()); // constructor "internal method" must be accessed differently: MethodType MT_newString = methodType(void.class); //()V for new String() try { assertEquals("impossible", lookup() .findVirtual(String.class, "<init>", MT_newString)); } catch (NoSuchMethodException ex) { } // OK MethodHandle MH_newString = publicLookup() .findConstructor(String.class, MT_newString); assertEquals("", (String) MH_newString.invokeExact());
refc
- the class or interface from which the method is accessedname
- the name of the methodtype
- the type of the method, with the receiver argument omittedNoSuchMethodException
- if the method does not existIllegalAccessException
- if access checking fails,
or if the method is static
,
or if the method is private
method of interface,
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsSecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException
The requested type must have a return type of void
.
(This is consistent with the JVM's treatment of constructor type descriptors.)
The returned method handle will have
variable arity if and only if
the constructor's variable arity modifier bit (0x0080
) is set.
If the returned method handle is invoked, the constructor's class will be initialized, if it has not already been initialized.
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle MH_newArrayList = publicLookup().findConstructor( ArrayList.class, methodType(void.class, Collection.class)); Collection orig = Arrays.asList("x", "y"); Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig); assert(orig != copy); assertEquals(orig, copy); // a variable-arity constructor: MethodHandle MH_newProcessBuilder = publicLookup().findConstructor( ProcessBuilder.class, methodType(void.class, String[].class)); ProcessBuilder pb = (ProcessBuilder) MH_newProcessBuilder.invoke("x", "y", "z"); assertEquals("[x, y, z]", pb.command().toString());
refc
- the class or interface from which the method is accessedtype
- the type of the method, with the receiver argument omitted, and a void return typeNoSuchMethodException
- if the constructor does not existIllegalAccessException
- if access checking fails
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsSecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException
Lookup
object. The static
initializer of the class is not run.
The lookup context here is determined by the lookup class, its class loader, and the lookup modes. In particular, the method first attempts to load the requested class, and then determines whether the class is accessible to this lookup object.
targetName
- the fully qualified name of the class to be looked up.SecurityException
- if a security manager is present and it
refuses accessLinkageError
- if the linkage failsClassNotFoundException
- if the class cannot be loaded by the lookup class' loader.IllegalAccessException
- if the class is not accessible, using the allowed access
modes.SecurityException
- if a security manager is present and it
refuses accesspublic Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException
Lookup
object. The
static initializer of the class is not run.
The lookup context here is determined by the lookup class and the lookup modes.
targetClass
- the class to be access-checkedIllegalAccessException
- if the class is not accessible from the lookup class, using the allowed access
modes.SecurityException
- if a security manager is present and it
refuses accesspublic MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException
invokespecial
instruction from within the explicitly specified specialCaller
.
The type of the method handle will be that of the method,
with a suitably restricted receiver type prepended.
(The receiver type will be specialCaller
or a subtype.)
The method and all its argument types must be accessible
to the lookup object.
Before method resolution, if the explicitly specified caller class is not identical with the lookup class, or if this lookup object does not have private access privileges, the access fails.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set.
(Note: JVM internal methods named "<init>"
are not visible to this API,
even though the invokespecial
instruction can refer to them
in special circumstances. Use findConstructor
to access instance initialization methods in a safe manner.)
Example:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... static class Listie extends ArrayList { public String toString() { return "[wee Listie]"; } static Lookup lookup() { return MethodHandles.lookup(); } } ... // no access to constructor via invokeSpecial: MethodHandle MH_newListie = Listie.lookup() .findConstructor(Listie.class, methodType(void.class)); Listie l = (Listie) MH_newListie.invokeExact(); try { assertEquals("impossible", Listie.lookup().findSpecial( Listie.class, "<init>", methodType(void.class), Listie.class)); } catch (NoSuchMethodException ex) { } // OK // access to super and self methods via invokeSpecial: MethodHandle MH_super = Listie.lookup().findSpecial( ArrayList.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_this = Listie.lookup().findSpecial( Listie.class, "toString" , methodType(String.class), Listie.class); MethodHandle MH_duper = Listie.lookup().findSpecial( Object.class, "toString" , methodType(String.class), Listie.class); assertEquals("[]", (String) MH_super.invokeExact(l)); assertEquals(""+l, (String) MH_this.invokeExact(l)); assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method try { assertEquals("inaccessible", Listie.lookup().findSpecial( String.class, "toString", methodType(String.class), Listie.class)); } catch (IllegalAccessException ex) { } // OK Listie subl = new Listie() { public String toString() { return "[subclass]"; } }; assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
refc
- the class or interface from which the method is accessedname
- the name of the method (which must not be "<init>")type
- the type of the method, with the receiver argument omittedspecialCaller
- the proposed calling class to perform the invokespecial
NoSuchMethodException
- if the method does not existIllegalAccessException
- if access checking fails,
or if the method is static
,
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsSecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
refc
- the class or interface from which the method is accessedname
- the field's nametype
- the field's typeNoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullfindVarHandle(Class, String, Class)
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
refc
- the class or interface from which the method is accessedname
- the field's nametype
- the field's typeNoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullfindVarHandle(Class, String, Class)
public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
name
of type type
declared in a class of type recv
.
The VarHandle's variable type is type
and it has one
coordinate type, recv
.
Access checking is performed immediately on behalf of the lookup class.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
final
, then the write, atomic
update, numeric atomic update, and bitwise atomic update access
modes are unsupported.
byte
,
short
, char
, int
, long
,
float
, or double
then numeric atomic update
access modes are unsupported.
boolean
,
byte
, short
, char
, int
or
long
then bitwise atomic update access modes are
unsupported.
If the field is declared volatile
then the returned VarHandle
will override access to the field (effectively ignore the
volatile
declaration) in accordance to its specified
access modes.
If the field type is float
or double
then numeric
and atomic update access modes compare values using their bitwise
representation (see Float.floatToRawIntBits(float)
and
Double.doubleToRawLongBits(double)
, respectively).
float
values or double
values,
as performed by the numeric and atomic update access modes, differ
from the primitive ==
operator and the Float.equals(java.lang.Object)
and Double.equals(java.lang.Object)
methods, specifically with respect to
comparing NaN values or comparing -0.0
with +0.0
.
Care should be taken when performing a compare and set or a compare
and exchange operation with such values since the operation may
unexpectedly fail.
There are many possible NaN values that are considered to be
NaN
in Java, although no IEEE 754 floating-point operation
provided by Java can distinguish between them. Operation failure can
occur if the expected or witness value is a NaN value and it is
transformed (perhaps in a platform specific manner) into another NaN
value, and thus has a different bitwise representation (see
Float.intBitsToFloat(int)
or Double.longBitsToDouble(long)
for more
details).
The values -0.0
and +0.0
have different bitwise
representations but are considered equal when using the primitive
==
operator. Operation failure can occur if, for example, a
numeric algorithm computes an expected value to be say -0.0
and previously computed the witness value to be say +0.0
.recv
- the receiver class, of type R
, that declares the
non-static fieldname
- the field's nametype
- the field's type, of type T
NoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
If the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
refc
- the class or interface from which the method is accessedname
- the field's nametype
- the field's typeNoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is not static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
If the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
refc
- the class or interface from which the method is accessedname
- the field's nametype
- the field's typeNoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is not static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException
name
of
type type
declared in a class of type decl
.
The VarHandle's variable type is type
and it has no
coordinate types.
Access checking is performed immediately on behalf of the lookup class.
If the returned VarHandle is operated on, the declaring class will be initialized, if it has not already been initialized.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
final
, then the write, atomic
update, numeric atomic update, and bitwise atomic update access
modes are unsupported.
byte
,
short
, char
, int
, long
,
float
, or double
, then numeric atomic update
access modes are unsupported.
boolean
,
byte
, short
, char
, int
or
long
then bitwise atomic update access modes are
unsupported.
If the field is declared volatile
then the returned VarHandle
will override access to the field (effectively ignore the
volatile
declaration) in accordance to its specified
access modes.
If the field type is float
or double
then numeric
and atomic update access modes compare values using their bitwise
representation (see Float.floatToRawIntBits(float)
and
Double.doubleToRawLongBits(double)
, respectively).
float
values or double
values,
as performed by the numeric and atomic update access modes, differ
from the primitive ==
operator and the Float.equals(java.lang.Object)
and Double.equals(java.lang.Object)
methods, specifically with respect to
comparing NaN values or comparing -0.0
with +0.0
.
Care should be taken when performing a compare and set or a compare
and exchange operation with such values since the operation may
unexpectedly fail.
There are many possible NaN values that are considered to be
NaN
in Java, although no IEEE 754 floating-point operation
provided by Java can distinguish between them. Operation failure can
occur if the expected or witness value is a NaN value and it is
transformed (perhaps in a platform specific manner) into another NaN
value, and thus has a different bitwise representation (see
Float.intBitsToFloat(int)
or Double.longBitsToDouble(long)
for more
details).
The values -0.0
and +0.0
have different bitwise
representations but are considered equal when using the primitive
==
operator. Operation failure can occur if, for example, a
numeric algorithm computes an expected value to be say -0.0
and previously computed the witness value to be say +0.0
.decl
- the class that declares the static fieldname
- the field's nametype
- the field's type, of type T
NoSuchFieldException
- if the field does not existIllegalAccessException
- if access checking fails, or if the field is not static
SecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullpublic MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException
defc
in which a method
of the given name and type is accessible to the lookup class.
The method and all its argument types must be accessible to the lookup object.
The type of the method handle will be that of the method,
without any insertion of an additional receiver parameter.
The given receiver will be bound into the method handle,
so that every call to the method handle will invoke the
requested method on the given receiver.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set
and the trailing array argument is not the only argument.
(If the trailing array argument is the only argument,
the given receiver value will be bound to it.)
This is almost equivalent to the following code, with some differences noted below:
whereimport static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle mh0 = lookup().findVirtual(defc, name, type); MethodHandle mh1 = mh0.bindTo(receiver); mh1 = mh1.withVarargs(mh0.isVarargsCollector()); return mh1;
defc
is either receiver.getClass()
or a super
type of that class, in which the requested method is accessible
to the lookup class.
(Unlike bind
, bindTo
does not preserve variable arity.
Also, bindTo
may throw a ClassCastException
in instances where bind
would
throw an IllegalAccessException
, as in the case where the member is protected
and
the receiver is restricted by findVirtual
to the lookup class.)receiver
- the object from which the method is accessedname
- the name of the methodtype
- the type of the method, with the receiver argument omittedNoSuchMethodException
- if the method does not existIllegalAccessException
- if access checking fails
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsSecurityException
- if a security manager is present and it
refuses accessNullPointerException
- if any argument is nullMethodHandle.bindTo(java.lang.Object)
,
findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType)
public MethodHandle unreflect(Method m) throws IllegalAccessException
accessible
flag is not set,
access checking is performed immediately on behalf of the lookup class.
If m is not public, do not share the resulting handle with untrusted parties.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set.
If m is static, and if the returned method handle is invoked, the method's class will be initialized, if it has not already been initialized.
m
- the reflected methodIllegalAccessException
- if access checking fails
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsNullPointerException
- if the argument is nullpublic MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException
invokespecial
instruction from within the explicitly specified specialCaller
.
The type of the method handle will be that of the method,
with a suitably restricted receiver type prepended.
(The receiver type will be specialCaller
or a subtype.)
If the method's accessible
flag is not set,
access checking is performed immediately on behalf of the lookup class,
as if invokespecial
instruction were being linked.
Before method resolution, if the explicitly specified caller class is not identical with the lookup class, or if this lookup object does not have private access privileges, the access fails.
The returned method handle will have
variable arity if and only if
the method's variable arity modifier bit (0x0080
) is set.
m
- the reflected methodspecialCaller
- the class nominally calling the methodIllegalAccessException
- if access checking fails,
or if the method is static
,
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsNullPointerException
- if any argument is nullpublic MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException
newInstance
operation,
creating a new instance of the constructor's class on the
arguments passed to the method handle.
If the constructor's accessible
flag is not set,
access checking is performed immediately on behalf of the lookup class.
The returned method handle will have
variable arity if and only if
the constructor's variable arity modifier bit (0x0080
) is set.
If the returned method handle is invoked, the constructor's class will be initialized, if it has not already been initialized.
c
- the reflected constructorIllegalAccessException
- if access checking fails
or if the method's variable arity modifier bit
is set and asVarargsCollector
failsNullPointerException
- if the argument is nullpublic MethodHandle unreflectGetter(Field f) throws IllegalAccessException
accessible
flag is not set,
access checking is performed immediately on behalf of the lookup class.
If the field is static, and if the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
f
- the reflected fieldIllegalAccessException
- if access checking failsNullPointerException
- if the argument is nullpublic MethodHandle unreflectSetter(Field f) throws IllegalAccessException
accessible
flag is not set,
access checking is performed immediately on behalf of the lookup class.
If the field is static, and if the returned method handle is invoked, the field's class will be initialized, if it has not already been initialized.
f
- the reflected fieldIllegalAccessException
- if access checking failsNullPointerException
- if the argument is nullpublic VarHandle unreflectVarHandle(Field f) throws IllegalAccessException
f
of type T
declared in a class of type R
.
The VarHandle's variable type is T
.
If the field is non-static the VarHandle has one coordinate type,
R
. Otherwise, the field is static, and the VarHandle has no
coordinate types.
Access checking is performed immediately on behalf of the lookup
class, regardless of the value of the field's accessible
flag.
If the field is static, and if the returned VarHandle is operated on, the field's declaring class will be initialized, if it has not already been initialized.
Certain access modes of the returned VarHandle are unsupported under the following conditions:
final
, then the write, atomic
update, numeric atomic update, and bitwise atomic update access
modes are unsupported.
byte
,
short
, char
, int
, long
,
float
, or double
then numeric atomic update
access modes are unsupported.
boolean
,
byte
, short
, char
, int
or
long
then bitwise atomic update access modes are
unsupported.
If the field is declared volatile
then the returned VarHandle
will override access to the field (effectively ignore the
volatile
declaration) in accordance to its specified
access modes.
If the field type is float
or double
then numeric
and atomic update access modes compare values using their bitwise
representation (see Float.floatToRawIntBits(float)
and
Double.doubleToRawLongBits(double)
, respectively).
float
values or double
values,
as performed by the numeric and atomic update access modes, differ
from the primitive ==
operator and the Float.equals(java.lang.Object)
and Double.equals(java.lang.Object)
methods, specifically with respect to
comparing NaN values or comparing -0.0
with +0.0
.
Care should be taken when performing a compare and set or a compare
and exchange operation with such values since the operation may
unexpectedly fail.
There are many possible NaN values that are considered to be
NaN
in Java, although no IEEE 754 floating-point operation
provided by Java can distinguish between them. Operation failure can
occur if the expected or witness value is a NaN value and it is
transformed (perhaps in a platform specific manner) into another NaN
value, and thus has a different bitwise representation (see
Float.intBitsToFloat(int)
or Double.longBitsToDouble(long)
for more
details).
The values -0.0
and +0.0
have different bitwise
representations but are considered equal when using the primitive
==
operator. Operation failure can occur if, for example, a
numeric algorithm computes an expected value to be say -0.0
and previously computed the witness value to be say +0.0
.f
- the reflected field, with a field of type T
, and
a declaring class of type R
IllegalAccessException
- if access checking failsNullPointerException
- if the argument is nullpublic MethodHandleInfo revealDirect(MethodHandle target)
target
- a direct method handle to crack into symbolic reference componentsSecurityException
- if a security manager is present and it
refuses accessIllegalArgumentException
- if the target is not a direct method handle or if access checking failsNullPointerException
- if the target is null
MethodHandleInfo
public boolean hasPrivateAccess()
true
if this lookup has PRIVATE
access.true
if this lookup has PRIVATE
access.Copyright © 1993, 2017, Oracle and/or its affiliates · All rights reserved · License