问题
MethodType methodType = MethodType.methodType(void.class, ByteBuffer.class);
MethodHandle handle = MethodHandles.publicLookup().findConstructor(type, methodType);
Function<ByteBuffer, Object> = handle; // ???
Is it possible to get the last assignment work? The inverted way does not work: Is it possible to convert method reference to MethodHandle?
Here another and copy-pastable example:
new Integer("123");
MethodType methodType = MethodType.methodType(void.class, String.class);
MethodHandle handle = MethodHandles.publicLookup().findConstructor(Integer.class, methodType);
Function<String, Integer> function1 = Integer::new;
Function<String, Integer> function2 = handle.toLambda(); // ???
回答1:
«This answer» contains a code example showing how to convert a MethodHandle
to a functional interface
implementation using the same feature, Java 8’s lambda expressions and method references use.
It’s all about calling LambdaMetafactory.metafactory with the method handle, the desired interface and the name of the sole abstract
method and required signature.
Both, the method’s documentation and it’s class documentation are very detailled.
So, for your request, example code may look like this:
MethodType methodType = MethodType.methodType(Integer.class, String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findStatic(Integer.class, "valueOf", methodType);
Function<String,Integer> f=(Function<String,Integer>)
LambdaMetafactory.metafactory(lookup, "apply",
MethodType.methodType(Function.class), methodType.generic(),
handle, methodType).getTarget().invokeExact();
System.out.println(f.apply("123"));
You have to care about the signature types here. The fourth parameter samMethodType
refers the the method type of the raw interface
’s functional signature, so for the raw type Function
we must implement Object apply(Object)
while the instantiatedMethodType
describes the method Integer apply(String)
. That’s why the method .generic()
is called on the methodType for the fourth parameter which will convert (String)Integer
to (Object)Object
.
This is even trickier for constructors as the constructor will be looked up with a (String)void
type while the functional type is the same as in the static
method case. So for a static
method the method’s MethodType
matches the MethodType
while for a constructor we have to use a different type for the lookup:
MethodType methodType = MethodType.methodType(Integer.class, String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findConstructor(
Integer.class, MethodType.methodType(void.class, String.class));
Function<String,Integer> f=(Function<String,Integer>)
LambdaMetafactory.metafactory(lookup, "apply",
MethodType.methodType(Function.class), methodType.generic(),
handle, methodType).getTarget().invokeExact();
But that’s only for completeness, for the type Integer
you shouldn’t call the constructor but use valueOf
method, preferably.
回答2:
I think you'll need something like:
Function<ByteBuffer,Object> fn = (Function<ByteBuffer,Object>)
MethodHandleProxies.asInterfaceInstance(Function.class, handle);
(Usual disclaimer: Not even compiled it. Compiled it. Seems to work.)
回答3:
Answer collection
No handle, just the lambda:
Function<String, Integer> function1 = Integer::new;
System.out.println(function1.apply("1"));
Simple (not generic, not exact) solution:
MethodType methodType = MethodType.methodType(void.class, String.class);
MethodHandle handle = MethodHandles.publicLookup().findConstructor(Integer.class, methodType);
Function<String, Integer> function2 = (s) -> {
try {
return (Integer) handle.invoke(s);
} catch (Throwable t) {
throw new Error(t);
}
};
System.out.println(function2.apply("2"));
Using LambdaMetafactory from Holger
MethodType methodType = MethodType.methodType(Integer.class, String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = lookup.findConstructor(Integer.class, MethodType.methodType(void.class, String.class));
Function<String,Integer> function3 = (Function<String,Integer>) LambdaMetafactory.metafactory(lookup, "apply", MethodType.methodType(Function.class), methodType.generic(), handle, methodType).getTarget().invokeExact();
System.out.println(function3.apply("3"));
Using MethodHandleProxies from Tom Hawtin
@SuppressWarnings("unchecked")
Function<String, Integer> function4 = (Function<String, Integer>) MethodHandleProxies.asInterfaceInstance(Function.class, handle);
System.out.println(function4.apply("4"));
来源:https://stackoverflow.com/questions/27417634/convert-methodhandle-to-method-reference-here-function