java.lang.invoke.LambdaConversionException:实例方法invokeVirtual的参数数量不正确

问题描述 投票:0回答:1
java package edu.project5;

import java.lang.invoke.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import static java.lang.invoke.MethodType.methodType;

public class LambdaExample {

    public static void main(String[] args) throws Throwable {
        // Define a simple record class
        record Person(String name, int age) {
        }

        // Create a LambdaMetafactory
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle methodHandle = lookup.findVirtual(Person.class, "name", methodType(String.class));

        CallSite callSite = LambdaMetafactory.metafactory(
            lookup,
            "get",
            MethodType.methodType(Supplier.class, Person.class),
            MethodType.methodType(String.class, Person.class),
            methodHandle,
            MethodType.methodType(String.class)
        );
        Person person = new Person("John", 30);

        MethodHandle factory = callSite.getTarget();
        Supplier<String> nameExtractor = (Supplier<String>) factory.invokeExact(person);

        // Create an instance of the record
        System.out.println("Extracted Name: " + nameExtractor.get());
    }

}

您好,由于某种原因,我无法制作一个 lambda 来调用一个人的名字并将其返回给我,我不太明白它是如何工作的,请帮忙

java record lambda-metafactory
1个回答
0
投票

我必须阅读文档几次才能完全理解需要传递哪些参数。

这部分对我来说是最清晰的解释:

当调用此方法返回的

CallSite
的目标时,生成的函数对象是一个类的实例,该类实现由
factoryType
返回类型命名的接口,声明一个由
interfaceMethodName
指定名称的方法以及
interfaceMethodType
的签名。

因此,factoryType 参数是生成供应商的参数。您编写的代码是正确的;它需要一个 Person 并生成一个 String:

MethodType.methodType(Supplier.class, Person.class),

下一个参数,interfaceMethodType,必须是Supplier.get()的签名。 get() 返回一个值但不带参数,因此您需要更改此设置:

MethodType.methodType(String.class, Person.class),

对此:

MethodType.methodType(Object.class),

为什么是对象而不是字符串?因为泛型是编译器的一个技巧。 Supply 的 get() 方法始终返回 Object(就像 List.get(int) 始终返回 Object 一样)。编译器强制执行正确的转换和类型检查,以模拟泛型类型安全。

您的 MethodHandle 是正确的。关于metafactory的最后一个参数,文档说:

dynamicMethodType
- 应在调用时动态强制执行的签名和返回类型。在简单的用例中,这与
interfaceMethodType
相同。

因此,我们再次希望通过

MethodType.methodType(Object.class)
来支持该论点。

整个事情看起来像这样:

CallSite callSite = LambdaMetafactory.metafactory(
    lookup,
    "get",
    MethodType.methodType(Supplier.class, Person.class),
    MethodType.methodType(Object.class),
    methodHandle,
    MethodType.methodType(Object.class)
);
© www.soinside.com 2019 - 2024. All rights reserved.