Gil*_*ili 6 java methodhandle lambda-metafactory
鉴于:
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Function;
class Testcase
{
@FunctionalInterface
public interface MyBuilder1<R>
{
R apply(String message);
}
@FunctionalInterface
public interface MyBuilder2<R>
{
R apply(Object message);
}
public static void main(String[] args) throws Throwable
{
Class<?> clazz = IllegalArgumentException.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class, String.class));
MethodHandle myFunctionConstructor = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(Function.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor1 = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(MyBuilder1.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor2 = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(MyBuilder2.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
@SuppressWarnings("unchecked")
Function<String, IllegalArgumentException> functionFactory =
(Function<String, IllegalArgumentException>) myFunctionConstructor.invokeExact();
@SuppressWarnings("unchecked")
MyBuilder1<IllegalArgumentException> myBuilder1Factory =
(MyBuilder1<IllegalArgumentException>) myBuilderConstructor1.invokeExact();
@SuppressWarnings("unchecked")
MyBuilder2<IllegalArgumentException> myBuilder2Factory =
(MyBuilder2<IllegalArgumentException>) myBuilderConstructor2.invokeExact();
IllegalArgumentException runFunction = functionFactory.apply("test");
// IllegalArgumentException runBuilder1 = myBuilder1Factory.apply("test");
IllegalArgumentException runBuilder2 = myBuilder2Factory.apply("test");
}
}
Run Code Online (Sandbox Code Playgroud)
为什么 dorunFunction和runBuilder2work whilerunBuilder1会抛出以下异常?
java.lang.AbstractMethodError:接收器类 Testcase$$Lambda$233/0x0000000800d21d88 未定义或继承接口 MyBuilder1 的已解析方法“抽象 java.lang.Object apply(java.lang.String)”的实现。
鉴于IllegalArgumentException构造函数采用String参数,而不是Object,JVM 是否应该接受runBuilder1并抱怨其他两个参数类型?
你MyBuilder1<R>有一个函数方法
R apply(String message);
Run Code Online (Sandbox Code Playgroud)
其擦除类型是
Object apply(String message);
Run Code Online (Sandbox Code Playgroud)
换句话说,与Functionor不同MyBuilder2,擦除的参数类型是String, 而不是Object。erase()的方法MethodType只是将所有引用类型替换为,这对于和 来说Object很方便,但不再适合了。对于非平凡类型,没有类似的简单方法。您必须包含专门针对您的情况的类型转换代码(除非您想通过反射查找接口方法)。FunctionMyBuilder2MyBuilder1
例如,我们可以将返回类型更改为Object并保留参数类型:
class Testcase
{
@FunctionalInterface
public interface MyBuilder1<R>
{
R apply(String message);
}
public static void main(String[] args) throws Throwable
{
Class<?> clazz = IllegalArgumentException.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz,
MethodType.methodType(void.class, String.class));
MethodHandle myBuilderConstructor1 = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(MyBuilder1.class),
mh.type().changeReturnType(Object.class), // instead of erase()
mh,
mh.type()
).getTarget();
@SuppressWarnings("unchecked")
MyBuilder1<IllegalArgumentException> myBuilder1Factory =
(MyBuilder1<IllegalArgumentException>) myBuilderConstructor1.invokeExact();
IllegalArgumentException runBuilder1 = myBuilder1Factory.apply("test");
runBuilder1.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
关于您的最后一个问题,擦除的类型是要实现的类型,而最后一个参数确定metafactory预期的类型,即从通用接口类型派生。必要时,生成的代码可能会进行从已擦除类型到此类型的类型转换。由于此类型在所有情况下都与构造函数签名匹配,因此所有变体都可以调用构造函数。
| 归档时间: |
|
| 查看次数: |
389 次 |
| 最近记录: |