それが反射して、オブジェクトからメソッド参照や関数オブジェクトを取得することは可能ですか?

user9613668:

クラスがあります。

class A {
    Mono<Response> testMap(Mono<Request> reqMono)
}

機能的なインターフェースがあります

interface MapHandler {
    Mono<?> handle(Mono<?> reqMono)
}

今、私はこれを書くことができます

{
A a = new A();
MapHandler handler = a::testMap;
}

そして、私は検出できるツール構築したいすべてのBean(オブジェクト)にMapHandlerをし、それらを収集します。

私はこれを試してみました。

List<MapHandler> list = initedList;
Method method = bean.getClass().getDeclaredMethods()[0];
list.put("methodName", req -> {
    return (Mono<?>) method.invoke(bean, req);
})

それはでそれを行うことは可能ですMethodHandleLambdaMetaFactory

HTNW:

明示的に使用するソリューションのラフスケッチLambdaMetafactoryあなたが望むように見える方法では、次のとおりです。

// the signature of the method returned by LambdaMetaFactory
// it takes an object of bean's type and makes a MapHandler that calls one
// of its instance methods
MethodType mkLambdaType = MethodType.methodType(MapHandler.class, bean.getClass());
// the signature of the method in MapHandler being implemented
MethodType handleType = MethodType.methodType(Mono.class, Mono.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();

// FYI this won't search in supertypes
// getMethods() will, but you only get public ones even if you have more privileged access
// you decide what to do here; the loop body is the important thing
for(Method method : bean.getClass().getDeclaredMethods()) {
    if(Modifier.isStatic(method.getModifiers())) continue;
    try {
        MethodHandle target = lookup.unreflect(method);
        CallSite mkLambda = LambdaMetafactory.metafactory
            (lookup, "handle", mkLambdaType, handleType, target, handleType);
        list.add((MapHandler)mkLambda.getTarget().invoke(bean));
    } catch(IllegalAccessException | LambdaConversionException e) {
        // because I am lazy, I'm not checking that method has the correct type
        // I'm letting LambdaMetafactory throw if that's not the case
        // if you choose not to use LambdaMetafactory, you may have to implement
        // this type-checking
        continue;
    } catch(Throwable t) {
        // Throwables come from the MethodHandle#invoke call
        // but nothing should be thrown at all, because LambdaMetafactory
        // produces its errors from metafactory, early, which are caught above
        throw new RuntimeException("Unexpected error during reflection", t);
    }
}

私は、これは非常に無駄であると考えています。一般的な実装は、LambdaMetafactoryそうで全く新しいクラスを作成しますmetafactory返し、呼び出しCallSiteコンストラクタまたは同様にポインティングを。各ことをこれは意味MapHandlerあなたが得るには、実行時に作成した、独自の匿名クラスです。これとは対照的に、呼び出すためにラムダを使ってあなたのオリジナルのアイデアは、MethodJVMに非常に良くあります。ラムダは、単一の作成原因とLambdaMetafactory保持し、クラス、methodおよびbeanインスタンス変数としてを。コードを通じて、最初の実行後にinvokedynamicブートストラップされ、それぞれがMapHandlerこの匿名クラスをインスタンス化するだけで作成されます。私のLambdaMetafactoryソリューションは、あなただけの比較的少数の必要がある場合は、許容できると思われるMapHandlerのが、しかしそれぞれがそれほど頻繁に呼び出されるのオーバーヘッドMethod#invoke 高すぎます。


だから私は先に行ってといくつかの簡単なベンチマークを行ってきました。あなたが初期化するご利用の場合、MapHandlerプログラム開始時にSをしてからちょうどそれらを起動し、私の技術とあなたはほぼ同じです。彼らは両方とも非常に速く、私は実際にはさまざまな種類のを起動するのにかかる時間に差を測定することができないということですMapHandler一般的には、LambdaMetafactory匿名クラスを作成するには時間がかかるので、悪いことです。実際には、あなたが作るより多くのクラスが、もはやそれがかかります。一方、method.invokeラムダは、単に数千倍速いことが多いです一つのオブジェクトを構築する必要があります。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=214405&siteId=1