0
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){
     ---
}

我收到此异常 java.lang.invoke.LambdaConversionException: Incorrect number of parameters for instance method invokeVirtual call:()void; 0个捕获参数,0个功能接口方法参数,0个实现参数

4

1 回答 1

4

此调用几乎所有错误:

  1. CallSite lambdaFactory = LambdaMetafactory.metafactory(
  2.   lookup,
  3.   "call",这必须是需要实现的接口方法的名称。因为BiConsumer,这是"accept"
  4.   MethodType.methodType(BiConsumer.class),这是调用类型,它必须与invoke(10) 处的调用匹配。
  5.   MethodType.methodType(void.class,Long.class),这是在字节码级别实现的接口方法的签名,即在类型擦除之后。因为BiConsumer,这总是MethodType.methodType(void.class, Object.class, Object.class)
  6.   lookup.findVirtual(CallClass.class, "call",
  7.     MethodType.methodType(void.class,Long.class)),
  8.   MethodType.methodType(void.class)这是接口的特殊化,或者当接口不是通用的时与 (5) 相同。在任何一种情况下,参数的数量都必须与 (5) 匹配。对于您的情况,您可能希望匹配目标方法,因此它必须是MethodType.methodType(void.class, CallClass.class, Long.class).
  9.   );
  10. lambdaFactory.getTarget().invoke(callId);invoke调用必须与(4) 中指定的invokedType签名相匹配。指定的参数是要捕获的值。由于您选择实现BiConsumer与目标方法具有相同功能签名的 ,因此没有使用附加值。

最大的问题是 (4) 和 (10) 之间的不匹配,因为它使您不清楚您真正想要实现的目标。您是要捕获现有callIdinvoke(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);
于 2020-02-19T18:23:14.183 回答