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