gpt4 book ai didi

java - 是否可以通过反射从对象中获取方法引用或函数对象?

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:45:05 24 4
gpt4 key购买 nike

有一个类。

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

有功能接口(interface)

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 来实现?

最佳答案

以您似乎想要的方式显式使用 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 都是它自己的匿名类,在运行时创建。相比之下,您最初使用 lambda 调用 Method 的想法对 JVM 来说要好得多。 lambda 导致创建单个 LambdaMetafactory 类,该类将 methodbean 作为实例变量。在第一次运行代码后,invokedynamic 被引导,每个 MapHandler 都是通过实例化这个匿名类来创建的。如果您只需要相对较少的 MapHandler,我的 LambdaMetafactory 解决方案似乎是可以接受的,但是每个都被调用得如此频繁,以至于 Method#invoke 的开销是太高了。


因此,我继续进行了一些快速基准测试。在您的用例中,您在程序启动时初始化 MapHandler,然后调用它们,我的技术和您的技术大致相同。它们都非常快,以至于我无法实际测量调用不同类型的 MapHandler 所花费的时间差异。一般来说,LambdaMetafactory 更糟糕,因为创建匿名类需要花费大量时间。事实上,你上的课越多,花的时间就越长。同时,method.invoke lambda 只需构造一个对象,这通常要快数千倍。

关于java - 是否可以通过反射从对象中获取方法引用或函数对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55774449/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com