如何从LambdaMetafactory解析“AbstractMethodError”

时间:2015-05-30 13:04:14

标签: java lambda method-reference

我从调用AbstractMethodError调用定义的方法中获取LambdaMetafactory#metafactory()。我无法弄清楚我做错了什么导致它。我已经看过很多在线使用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)

我要做的是创建一个具有单个字段的类,该字段可以直接分配lambda,或者通过查找类名和方法名来分配。二元性的原因是抽象出指定调用方法的方式(直接在代码中指定,或在配置文件中指定)。

附加代码定义了一个功能接口ListMaker,其中的方法根据对象的字符串表示形式生成1个元素的列表。它包含一个静态方法listify,它实现了一个匹配接口方法签名的函数,并将用于样本的set-the-method-direct部分。

以下是代码:

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);
  }
}

我已经能够理解我在网上找到的类似例子,但它们都是最终结果;我无法找到任何足够描述性的东西(至少对我而言) 最终结果的来源,以帮助我弄清楚我做错了什么。

1 个答案:

答案 0 :(得分:3)

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

我接受了您的代码,删除了对.generic()的调用,您的代码成功运行。

documentation for the generic() method表示此方法会将其调用的MethodType内的所有类型转换为Object。 h.type()是获取Object并返回List的方法的签名,而h.type().generic()是获取Object并返回Object的方法的签名。

我不认为generic()方法与泛型类型有任何关系。请不要因为功能界面中的方法具有泛型类型的参数而觉得必须使用它。我承认我之前没有遇到过这种方法,但我认为它有一个令人困惑的名字。