Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否可以通过反射从对象获取方法引用或函数对象?_Java_Java 8 - Fatal编程技术网

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

Java 是否可以通过反射从对象获取方法引用或函数对象?,java,java-8,Java,Java 8,有一节课 class A { Mono<Response> testMap(Mono<Request> reqMono) } 我想构建一个工具,可以检测bean(对象)中的所有映射处理程序并收集它们 我试过这个 List<MapHandler> list = initedList; Method method = bean.getClass().getDeclaredMethods()[0]; list.put("methodName", req -

有一节课

class A {
    Mono<Response> testMap(Mono<Request> reqMono)
}
我想构建一个工具,可以检测bean(对象)中的所有映射处理程序并收集它们

我试过这个

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

是否可以通过
MethodHandle
LambdaMetaFactory
来实现这一点?

以您希望的方式显式使用
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调用
方法
的最初想法对JVM更有利。lambda导致创建一个
LambdaMetafactory
类,该类将
方法
bean
作为实例变量。在第一次运行代码(其中
invokedynamic
是引导的)之后,每个
MapHandler
都是通过实例化这个匿名类创建的。只有当您只需要相对较少的
MapHandler
s时,我的
LambdaMetafactory
解决方案才显得可以接受,但每次调用都非常频繁,以至于
方法调用的开销太高



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

>这意味着您得到的每个MapHandler都是它自己的匿名类。我的解决方案是
()->{}
包装
method.invoke()
,在编译阶段LambdaMetafactory似乎做了同样的事情,但调用
方法#invoke
>
方法#invoke
的开销太高。您的解决方案似乎通过创建一个新的
映射处理程序来减少
方法#invoke
。我可以问一个新问题吗?如果我不关心编译性能和这个工具的性能,只关心创建的函数是否会因为反射而影响性能。我的解决方案和您的解决方案创建的函数之间有什么区别吗?是的,此解决方案减少了
Method\invoke
调用的数量。不,那还不够好,不能比你的快。您的创建了一个匿名类。该类在第一次执行代码时在运行时生成,然后重新使用。这将在运行时为每个
MapHandler
生成全新的类。它贵得离谱。编译性能与此无关。此外,一旦有了
方法
,调用
invoke
的速度只有调用该方法的两倍。反射的真正代价是查找
方法,这需要10倍的时间。我不确定由
LambdaMetafactory创建的函数对象是否比调用
方法.invoke()快。我目前正在测试它。如果您在同一
方法
对象上调用
invoke
的次数足够多,它也会在后台生成一个新的invoker类。中间解决方案是使用
unreflect
返回的直接
MethodHandle
进行调用。但是由于问题的代码片段表明将维护从方法名到实际调用代码的
映射,我会毫不犹豫地使用
LambdaMetafactory
生成的类,因为数量是有限的,而且易于管理……您想检测某个bean中符合
MapHandler
声明的所有方法吗?您拥有的代码1)不会编译
invode
vs
invoke
2)如果该方法符合
MapHandler
的要求,则不会“测试”-是否需要更清楚一点?
List<MapHandler> list = initedList;
Method method = bean.getClass().getDeclaredMethods()[0];
list.put("methodName", req -> {
    return (Mono<?>) method.invoke(bean, req);
})
// 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);
    }
}