4

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)

私がやろうとしているのは、ラムダを直接割り当てるか、クラス名とメソッド名のルックアップによって割り当てることができる単一のフィールドを持つクラスを作成することです。二重性の理由は、呼び出されるメソッドが指定された方法 (コードで直接指定されるか、構成ファイルで指定されるか) を抽象化するためです。

添付のコードはListMaker、オブジェクトの文字列表現から 1 要素のリストを生成するメソッドを使用して、関数インターフェイスを定義します。これには、インターフェイスのメソッドのシグネチャに一致する関数を実装する静的メソッドが含まれておりlistify、サンプルの set-the-method-directly 部分に使用されます。

コードは次のとおりです。

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

オンラインで見つけた同様の例を理解できましたが、それらはすべて最終結果です。私が間違っていることを理解するのに役立つ最終結果がどのように導き出されたかについて、 (少なくとも私にとっては)十分に説明的なものを見つけることができませんでした。

4

1 に答える 1

3

エラーは、への呼び出し.generic()で inを使用していると思います。handle.type().generic()LambdaMetafactory.metafactory()

私はあなたのコードを取り、への呼び出しを削除し.generic()、あなたのコードは正常に実行されました.

メソッドドキュメントにgeneric()MethodTypeよると、このメソッドは呼び出されたオブジェクト 内のすべての型を Object に変換します。h.type()は、オブジェクトを受け取ってリストを返すh.type().generic()メソッドのシグネチャであり、オブジェクトを受け取ってオブジェクトを返すメソッドのシグネチャです。

generic()メソッドがジェネリック型とは何の関係もないと思います。関数インターフェイスのメソッドにジェネリック型のパラメーターがあるという理由だけで、それを使用する必要があるとは思わないでください。私は以前にこのメソッドに出くわしたことがなかったことを認めますが、紛らわしい名前が付いていると思います.

于 2015-05-30T13:57:58.727 に答える