gpt4 book ai didi

java - LambdaMetaFactory 中的类型

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:22:16 26 4
gpt4 key购买 nike

当我调用 metafactory 时出现异常。它说:

java.lang.invoke.LambdaConversionException:
Incorrect number of parameters for instance method
invokeVirtual my.ExecuteTest$AProcess.step_1:()Boolean;
0 captured parameters,
0 functional interface method parameters,
0 implementation parameters

LambdaMetafactory.metafactory 的文档我没有完全理解。我在找出正确的参数时遇到问题:

  • MethodHandles.Lookup caller -- 很简单
  • String invokedName -- 我在这里相当确定
  • MethodType invokedType -- 这是什么?
  • MethodType samMethodType -- 错误...不确定
  • MethodHandle implMethod -- 很好
  • MethodType instantiatedMethodType -- 又是什么?第二次?

因此归结为:

  • 方法类型调用类型
  • 方法类型 samMethodType
  • 方法类型实例化方法类型

我的代码是这样的:

package my;

import java.lang.invoke.*;
import java.lang.reflect.Method;

public class Execute {

public interface ProcessBase {};

@FunctionalInterface
public interface Step {
Boolean apply();
}

public Step getMethodFromStepid(ProcessBase process, int stepid) {
try {
// standard reflection stuff
final MethodHandle unreflect = caller.unreflect(method);
final String mname = "step_"+stepid;
// new java8 method reference stuff
final Method method = process.getClass().getMethod(mname);
final MethodType type=MethodType.methodType(Boolean.class);
final MethodType stepType=MethodType.methodType(Step.class);
final MethodHandles.Lookup caller = MethodHandles.lookup();
final CallSite site = LambdaMetafactory.metafactory(
caller, "apply", stepType, type, unreflect, type); // damn
// convert site to my method reference
final MethodHandle factory = site.getTarget();
final Step step = (Step) factory.invoke();
return step;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
}

通过测试

package my;

import org.junit.Test;
import static org.junit.Assert.*;

public class ExecuteTest {

private class AProcess implements Execute.ProcessBase {
public Boolean step_1() { return true; }
public Boolean step_2() { return false; }
}

@Test
public void getMethodFromStepid() throws Exception {
final AProcess process = new AProcess();
{
final Execute.Step methodRef = instance.getMethodFromStepid(process, 1);
final boolean result = methodRef.apply();
assertTrue(result);
}
{
final Execute.Step methodRef = instance.getMethodFromStepid(process, 2);
final boolean result = methodRef.apply();
assertFalse(result);
}
}

private final Execute instance = new Execute();

}

最佳答案

前三个参数不是 lambda 表达式特有的,而是 invokedynamicbootstrap 方法 的标准参数操作说明。 lookup参数封装了调用者的上下文,invokedNameinvokedType参数表示 invokedynamic 的名称和类型说明。

这取决于 Bootstrap 方法来分配更多语义。由于在这种情况下,这条指令的目的是产生一个 lambda 表达式实例,它将消耗捕获的值并产生一个 interface。实例。所以 invokedType将具有反射(reflect)捕获值类型的参数类型,或者对于非捕获 lambda 是无参数的,并且具有与所需的功能接口(interface)匹配的返回类型。 invokedName用于指定功能接口(interface)的方法名称,这是不寻常的,因为它实际上并没有在这里被调用,但是由于被调用的名称没有其他含义,所以这里重用了这个参数。

samMethodType是要实现的功能接口(interface)方法的签名(在字节码级别),与 instantiatedMethodType 相同只要,例如不涉及泛型。否则,samMethodType将被类型删除,而 instantiatedMethodType包含实际的类型参数,例如实现 Function<String,Integer>

  • invokedType返回类型为 Function
  • samMethodType将是 (Object)Object
  • instantiatedMethodType将是 (String)Integer

请注意,对于您的特定情况,类型基本上是正确的,但是由于您要在提供的 process 上调用目标方法例如,你必须将它绑定(bind)到 lambda 实例(你甚至没有尝试)。不幸的是,您在问题中没有明确说明您遇到了什么样的实际问题(即您得到了 LambdaConversionException ),所以我之前没有注意到这个问题。

如上所述,invokedType必须包含要捕获为参数类型的值的类型。然后,您必须传递实际的 process实例到 invoke称呼。顾名思义,invokedType必须匹配 invoke 的类型:

public Step getMethodFromStepid(ProcessBase process, int stepid) {
try {
// standard reflection stuff
final String mname = "step_"+stepid;
final Method method = process.getClass().getMethod(mname);
// new java8 method reference stuff
final MethodType type=MethodType.methodType(Boolean.class);
// invokedType: bind process, generate Step
final MethodType stepType=MethodType.methodType(Step.class,process.getClass());
final MethodHandles.Lookup caller = MethodHandles.lookup();
final MethodHandle unreflect = caller.unreflect(method);
final CallSite site = LambdaMetafactory.metafactory(
caller, "apply", stepType, type, unreflect, type);
// convert site to my method reference
final MethodHandle factory = site.getTarget();
// pass the value to bind and get the functional interface instance
final Step step = (Step)factory.invoke(process);
return step;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}

关于java - LambdaMetaFactory 中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39640547/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com