如何从 LambdaMetafactory 解析 "AbstractMethodError"

How to resolve "AbstractMethodError" from LambdaMetafactory

我通过调用由对 LambdaMetafactory#metafactory() 的调用定义的方法得到 AbstractMethodError。我不知道我做错了什么导致它。我在网上查看了很多使用 LambdaMetafactory#metafactory() 的示例,但没有找到任何与我正在尝试做的完全匹配的东西。

这是 运行 附加代码的 [全部] 输出:

Result[0] = "version 1"
Result[0] = "1"
Exception in thread "main" java.lang.AbstractMethodError
    at junk.LMTest.invokeMaker(LMTest.java:52)
    at junk.LMTest.main(LMTest.java:65)

我想做的是创建一个 class,它有一个可以直接分配给 lambda 的字段,或者通过查找 class 名称和方法名称来分配.双重性的原因是抽象出指定调用方法的方式(直接在代码中指定,或在配置文件中指定)。

附加代码定义了一个函数式接口 ListMaker,其中包含一个从对象的字符串表示形式生成 1 元素列表的方法。它包含一个静态方法 listify,该方法实现了一个与接口方法签名相匹配的函数,并将用于示例的直接设置方法部分。

代码如下:

package junk;

import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class LMTest
{

  @FunctionalInterface
  public interface ListMaker
  {
    public List<String> makeList(Object obj);
  }

  private ListMaker maker;

  public static List<String> listify(Object obj)
  {
    List<String> l = new ArrayList<>();
    l.add(obj.toString());
    return l;
  }

  public void setMaker(ListMaker maker)
  {
    this.maker = maker;
  }

  public void setMaker(String className, String methodName)
      throws Throwable
  {
    Method m = Class.forName(className).getDeclaredMethod(methodName, Object.class);
    MethodHandles.Lookup l = MethodHandles.lookup();
    MethodHandle handle = l.unreflect(m);
    CallSite cs = LambdaMetafactory.metafactory(l,
                                                "makeList",
                                                MethodType.methodType(ListMaker.class),
                                                handle.type().generic(),
                                                handle,
                                                handle.type());
    maker = (ListMaker)cs.getTarget().invoke();
  }

  public void invokeMaker(Object obj)
  {
    String result0 = maker.makeList(obj).get(0);
    System.out.println("Result[0] = \"" + result0 + "\"");
  }

  public static void main(String[] args)
      throws Throwable
  {
    LMTest lmt = new LMTest();
    lmt.setMaker(LMTest::listify);
    lmt.invokeMaker("version 1");
    lmt.invokeMaker(1);
    //
    lmt.setMaker("junk.LMTest", "listify");
    lmt.invokeMaker("version 2");
    lmt.invokeMaker(2);
  }
}

网上找的类似的例子我也能看懂,但都是最终结果;我还没有找到足够的描述(至少对我来说)如何最终结果是如何推导出来的,以帮助我弄清楚我做错了什么。

我认为错误是在调用 LambdaMetafactory.metafactory() 时在 handle.type().generic() 中使用了 .generic()

我获取了你的代码,成功移除了对 .generic() 的调用和你的代码 运行。

documentation for the generic() method 表示此方法将调用它的 MethodType 中的所有类型转换为 Object。 h.type() 是采用对象和 returns 列表的方法的签名,而 h.type().generic() 是采用对象和 returns 对象的方法的签名。

我不认为 generic() 方法与泛型类型有任何关系。请不要仅仅因为函数式接口中的方法具有泛型类型的参数就觉得您必须使用它。我承认我以前没有遇到过这种方法,但我认为它的名称令人困惑。