此调用几乎所有错误:
CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
这必须是需要实现的接口方法的名称。因为BiConsumer
,这是"accept"
。
MethodType.methodType(BiConsumer.class),
这是调用类型,它必须与invoke
(10) 处的调用匹配。
MethodType.methodType(void.class,Long.class),
这是在字节码级别实现的接口方法的签名,即在类型擦除之后。因为BiConsumer
,这总是MethodType.methodType(void.class, Object.class, Object.class)
。
lookup.findVirtual(CallClass.class, "call",
MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class)
这是接口的特殊化,或者当接口不是通用的时与 (5) 相同。在任何一种情况下,参数的数量都必须与 (5) 匹配。对于您的情况,您可能希望匹配目标方法,因此它必须是MethodType.methodType(void.class, CallClass.class, Long.class)
.
);
lambdaFactory.getTarget().invoke(callId);
该invoke
调用必须与(4) 中指定的invokedType签名相匹配。指定的参数是要捕获的值。由于您选择实现BiConsumer
与目标方法具有相同功能签名的 ,因此没有使用附加值。
最大的问题是 (4) 和 (10) 之间的不匹配,因为它使您不清楚您真正想要实现的目标。您是要捕获现有callId
的invoke(callId)
建议还是要创建一个非捕获函数,作为invokedType参数和BiConsumer
建议的选择?
对于直接BiConsumer
生成,固定代码如下所示:
CallSite callSite = LambdaMetafactory.metafactory(
lookup, "accept", MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class, Object.class, Object.class),
lookup.findVirtual(CallClass.class,"call", MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class, CallClass.class, Long.class)
);
BiConsumer<CallClass,Long> bc = (BiConsumer<CallClass, Long>)callSite.getTarget().invoke();
如果要捕获现有的callId
,则必须将功能接口更改为不需要第二个参数的类型。此外,您需要一个适配器,因为LambdaMetafactory
首先需要捕获的参数,然后是接口方法参数。因此,由于不直接支持这一点,最简单的解决方案是生成BiConsumer<CallClass,Long>
如上的 a,然后Consumer<CallClass> c = cc -> bc.apply(cc, callId);
捕获现有的callId
.
CallClass
仅当您还具有要绑定的现有实例时,才可以直接进行:
CallSite callSite = LambdaMetafactory.metafactory(
lookup, "run", MethodType.methodType(Runnable.class, LambdaMF.class, Long.class),
MethodType.methodType(void.class),
lookup.findVirtual(LambdaMF.class, "call", MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class)
);
Runnable r = (Runnable)callSite.getTarget().invoke(callClassInstance, callId);