Java lambda元工厂
CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class,Long.class),
lookup.findVirtual(CallClass.class, "call",
MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class));
lambdaFactory.getTarget().invoke(callId);
private void call(Long callId){
---
}
我得到了这个例外 JAVAlang.invoke。LambdaConversionException:实例方法invokeVirtual调用()的参数数量不正确,无效;0个捕获参数,0个功能接口方法参数,0个实现参数
# 1 楼答案
这一调用几乎完全错误:
CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
这必须是需要实现的接口方法的名称。对于BiConsumer
,这是"accept"
李>MethodType.methodType(BiConsumer.class),
这是invokedType,它必须匹配(10)处的invoke
调用李>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)之间的不匹配,因为它不清楚您实际想要实现什么。您想按照
invoke(callId)
的建议捕获现有的callId
,还是按照invokedType参数和BiConsumer
选项的建议创建一个非捕获函数对于直接的
BiConsumer
生成,固定代码如下所示:如果要捕获现有的
callId
,必须将函数接口更改为不需要第二个参数的类型。此外,您还需要一个适配器,因为LambdaMetafactory
首先需要捕获的参数,然后需要接口方法参数。因此,由于不直接支持这一点,最简单的解决方案是如上所述生成BiConsumer<CallClass,Long>
,然后生成Consumer<CallClass> c = cc -> bc.apply(cc, callId);
,捕获现有的callId
只有当您还有一个已经存在的
CallClass
实例要绑定时,才可以直接进行绑定: