|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object sun.dyn.MethodHandleImpl java.dyn.MethodHandle sun.dyn.BoundMethodHandle java.dyn.JavaMethodHandle
public abstract class JavaMethodHandle
Disabled: no SafeJ information.
A Java method handle extends the basic method handle type with additional
programmer defined methods and fields.
Its behavior as a method handle is determined at instance creation time,
by providing the new instance with an "entry point" method handle
to handle calls. This entry point must accept a leading argument
whose type is the Java method handle itself or a supertype, and the
entry point is always called with the Java method handle itself as
the first argument. This is similar to ordinary virtual methods, which also
accept the receiver object this
as an implicit leading argument.
The MethodType
of the Java method handle is the same as that
of the entry point method handle, with the leading parameter type
omitted.
Here is an example of usage, creating a hybrid object/functional datum:
class Greeter extends JavaMethodHandle { private String greeting = "hello"; public void setGreeting(String s) { greeting = s; } public void run() { System.out.println(greeting+", "+greetee); } private final String greetee; Greeter(String greetee) { super(RUN); // alternatively, super("run") this.greetee = greetee; } // the entry point function is computed once: private static final MethodHandle RUN = MethodHandles.lookup().findVirtual(Greeter.class, "run", MethodType.make(void.class)); } // class Main { public static void main(String... av) { ... Greeter greeter = new Greeter("world"); greeter.run(); // prints "hello, world" // Statically typed method handle invocation (most direct): MethodHandle mh = greeter; mh.<void>invoke(); // also prints "hello, world" // Dynamically typed method handle invocation: MethodHandles.invoke(greeter); // also prints "hello, world" greeter.setGreeting("howdy"); mh.invoke(); // prints "howdy, world" (object-like mutable behavior)
In the example of Greeter
, the method run
provides the entry point.
The entry point need not be a constant value; it may be independently
computed in each call to the constructor. The entry point does not
even need to be a method on the Greeter
class, though
that is the typical case.
The entry point may also be provided symbolically, in which case the the
JavaMethodHandle
constructor performs the lookup of the entry point.
This makes it possible to use JavaMethodHandle
to create an anonymous
inner class:
// We can also do this with symbolic names and/or inner classes: MethodHandles.invoke(new JavaMethodHandle("yow") { void yow() { System.out.println("yow, world"); } });
Here is similar lower-level code which works in terms of a bound method handle.
Note that the method handle must be separately created as a view on the base object. This increases footprint, complexity, and dynamic indirections.class Greeter { public void run() { System.out.println("hello, "+greetee); } private final String greetee; Greeter(String greetee) { this.greetee = greetee; } // the entry point function is computed once: private static final MethodHandle RUN = MethodHandles.findVirtual(Greeter.class, "run", MethodType.make(void.class)); } // class Main { public static void main(String... av) { ... Greeter greeter = new Greeter("world"); greeter.run(); // prints "hello, world" MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter); mh.invoke(); // also prints "hello, world"
Here is a pure functional value expressed most concisely as an anonymous inner class:
// class Main { public static void main(String... av) { ... final String greetee = "world"; MethodHandle greeter = new JavaMethodHandle("run") { private void run() { System.out.println("hello, "+greetee); } } greeter.invoke(); // prints "hello, world"
Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle, and instantiated as an anonymous class. The data structure is a handle to 1-D array, with a specialized index type (long). It is created by inner class, and uses signature-polymorphic APIs throughout.
abstract class AssignableMethodHandle extends JavaMethodHandle { private final MethodHandle setter; public MethodHandle setter() { return setter; } public AssignableMethodHandle(String get, String set) { super(get); MethodType getType = this.type(); MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class); this.setter = MethodHandles.publicLookup().bind(this, set, setType); } } // class Main { public static void main(String... av) { ... final Number[] stuff = { 123, 456 }; AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") { public Number get(long i) { return stuff[(int)i]; } public void set(long i, Object x) { stuff[(int)i] = x; } } int x = (Integer) stuffPtr.<Number>invoke(1L); // 456 stuffPtr.setter().<void>invoke(0L, (Number) 789); // replaces 123 with 789
MethodHandle
Nested Class Summary |
---|
Nested classes/interfaces inherited from class sun.dyn.MethodHandleImpl |
---|
sun.dyn.MethodHandleImpl.MethodHandleFriend |
Field Summary |
---|
Fields inherited from class sun.dyn.MethodHandleImpl |
---|
vmtarget |
Constructor Summary | |
---|---|
protected |
JavaMethodHandle(MethodHandle entryPoint)
When creating a JavaMethodHandle , the actual method handle
invocation behavior will be delegated to the specified entryPoint . |
protected |
JavaMethodHandle(String entryPointName)
Create a method handle whose entry point is a non-static method visible in the exact (most specific) class of the newly constructed object. |
protected |
JavaMethodHandle(String entryPointName,
MethodType type)
Create a method handle whose entry point is a non-static method visible in the exact (most specific) class of the newly constructed object. |
Method Summary |
---|
Methods inherited from class sun.dyn.BoundMethodHandle |
---|
toString |
Methods inherited from class java.dyn.MethodHandle |
---|
asCollector, asSpreader, asType, bindTo, invokeExact, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeGeneric, invokeVarargs, invokeVarargs, type |
Methods inherited from class sun.dyn.MethodHandleImpl |
---|
accessArrayElement, accessField, addTypeString, bindArgument, bindReceiver, checkSpreadArgument, collectArguments, convertArguments, dropArguments, filterArgument, findMethod, foldArguments, getLookup, getNameString, init, initLookup, initStatics, makeGuardWithCatch, makeGuardWithTest, raiseException, setMethodHandleFriend, spreadArguments, throwException |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Constructor Detail |
---|
protected JavaMethodHandle(MethodHandle entryPoint)
JavaMethodHandle
, the actual method handle
invocation behavior will be delegated to the specified entryPoint
.
This may be any method handle which can take the newly constructed object
as a leading parameter.
The method handle type of this
(i.e, the fully constructed object)
will be entryPoint
, minus the leading argument.
The leading argument will be bound to this
on every method
handle invocation.
entryPoint
- the method handle to handle callsprotected JavaMethodHandle(String entryPointName, MethodType type)
The method is specified by name and type, as if via this expression:
MethodHandles.lookup().findVirtual(this.getClass(), name, type)
.
The class defining the method might be an anonymous inner class.
The method handle type of this
(i.e, the fully constructed object)
will be the given method handle type.
A call to this
will invoke the selected method.
The receiver argument will be bound to this
on every method
handle invocation.
Rationale:
Although this constructor may seem to be a mere luxury,
it is not subsumed by the more general constructor which
takes any MethodHandle
as the entry point argument.
In order to convert an entry point name to a method handle,
the self-class of the object is required (in order to do
the lookup). The self-class, in turn, is generally not
available at the time of the constructor invocation,
due to the rules of Java and the JVM verifier.
One cannot call this.getClass()
, because
the value of this
is inaccessible at the point
of the constructor call. (Changing this would require
change to the Java language, verifiers, and compilers.)
In particular, this constructor allows JavaMethodHandle
s
to be created in combination with the anonymous inner class syntax.
entryPointName
- the name of the entry point methodtype
- (optional) the desired type of the method handleprotected JavaMethodHandle(String entryPointName)
The method is specified only by name. There must be exactly one method of that name visible in the object class, either inherited or locally declared. (That is, the method must not be overloaded.)
The method handle type of this
(i.e, the fully constructed object)
will be the same as the type of the selected non-static method.
The receiver argument will be bound to this
on every method
handle invocation.
ISSUE: This signature wildcarding feature does not correspond to any MethodHandles.Lookup API element. Can we eliminate it? Alternatively, it is useful for naming non-overloaded methods. Shall we make type arguments optional in the Lookup methods, throwing an error in cases of ambiguity?
For this method's rationale, see the documentation
for JavaMethodHandle(String,MethodType)
.
entryPointName
- the name of the entry point method
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |