将java.lang.reflect.Method强制转换为函数接口

将java.lang.reflect.Method强制转换为函数接口,java,reflection,Java,Reflection,很难找到这个话题的任何线索。我所能找到的只是关于将一个函数接口转换为另一个函数接口的问题,以及一些关于Java中类型转换的文章。不是我想要的 问题是如何转换lambda→ 方法,我希望相反,转换为任何功能接口,例如,to 我找到的方法是围绕方法#invoke方法创建一个lambda适配器: public void registerCallbacks(带注释的最终对象){ Class clazz=annotated.getClass(); for(方法:clazz.getDeclaredMetho

很难找到这个话题的任何线索。我所能找到的只是关于将一个函数接口转换为另一个函数接口的问题,以及一些关于Java中类型转换的文章。不是我想要的

问题是如何转换
lambda→ 方法
,我希望相反,转换为任何功能接口,例如,to

我找到的方法是围绕
方法#invoke
方法创建一个lambda适配器:

public void registerCallbacks(带注释的最终对象){
Class clazz=annotated.getClass();
for(方法:clazz.getDeclaredMethods()){
if(方法.isAnnotationPresent(Callback.class)){
回调注册=method.getAnnotation(Callback.class);
列表警告=新的ArrayList(3);
如果(!Modifier.isPublic(method.getModifiers()))
warnings.add(String.format(“方法%s必须是公共的”,方法));
if(method.getParameterCount()!=1)
warnings.add(String.format(“方法%s只能使用一个参数”,方法));
如果(method.getParameterCount()==1&&!method.getParameterTypes()[0]。等于(Integer.class))
warnings.add(String.format(“方法%s必须使用%s”,方法,Integer.class));
如果(!warnings.isEmpty()){
warnings.forEach(日志::warn);
继续;
}
回调\映射器注册表回调((参数)->{
试一试{
方法调用(带注释,参数);
}捕获(IllegalAccessException | InvocationTargetException e){
//由于之前的检查不应发生。
log.warn(String.format(“无法用%s调用%s上的%s”,方法,带注释,参数),e);
}
});
info(“将{}注册为回调”,方法);
}
}
}
然而,我想避免写作

CALLBACKS\u MAPPER.registerCallback((参数)->{
试一试{
方法调用(带注释,参数);
}捕获(IllegalAccessException | InvocationTargetException e){
//由于之前的检查不应发生。
log.warn(String.format(“无法用%s调用%s上的%s”,方法,带注释,参数),e);
}
});
喜欢更简单的东西,比如

CALLBACKS\u MAPPER.registerCallback(SomeApacheLib.methodToFunction(带注释的方法));

➥ 那么,有没有一种方法可以将旧的Java 1.1反射库映射到新的Java 8功能接口,或者是我太笨了,上面提到的使用lambda的解决方案就可以了?

如果您满足于在引擎盖下使用反射,只需不喜欢
调用
try
/
catch
,您只需创建一个简单的实用程序函数,如:

public static <T> Consumer<T> toConsumer(Object annotated, Method m) {
    return param -> {
        try {
            m.invoke(annotated, param);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    };
}
但是,如果您想要完全避免反射,您可以使用
LambdaMetafactory
创建
使用者

static Consumer<String> toConsumer(MethodHandles.Lookup lookup, Object annotated, Method method) throws Throwable {
    MethodType consumeString = MethodType.methodType(void.class, String.class);
    MethodHandle handle = lookup.unreflect(method);
    final CallSite site = LambdaMetafactory.metafactory(lookup, "accept",
            MethodType.methodType(Consumer.class, annotated.getClass()),
            consumeString.changeParameterType(0, Object.class),
            handle,
            consumeString);
    return (Consumer<String>) site.getTarget().invoke(annotated);
}

当然,这里唯一合适的解决方案是重构代码,使用已知的回调接口,通常可以在该接口上调用定义的方法,而不是传递
方法
s。

可能重复@CodeMatrix,不幸的是,这不是它。虽然理解这个解决方案很有趣。谢谢:)参考问题是关于转换
lambda的→ 方法
我想要的是
方法→ lambda
。不过,这个问题中的技巧似乎对我没有帮助。谢谢你的回答!是的,我想我试图在运行时避免反射,以避免重复的
invoke
调用。我从来都不知道什么是LambdaMetaFactory。这就是我问题的答案。谢谢。此外,我认为使用注释将方法标记为回调是一个好主意,但是如果我将来遇到这种需要,也许我真的应该创建像
interface CallbackProvider{List getCallbacks();}
这样的接口?。。我会考虑的
static Consumer<String> toConsumer(MethodHandles.Lookup lookup, Object annotated, Method method) throws Throwable {
    MethodType consumeString = MethodType.methodType(void.class, String.class);
    MethodHandle handle = lookup.unreflect(method);
    final CallSite site = LambdaMetafactory.metafactory(lookup, "accept",
            MethodType.methodType(Consumer.class, annotated.getClass()),
            consumeString.changeParameterType(0, Object.class),
            handle,
            consumeString);
    return (Consumer<String>) site.getTarget().invoke(annotated);
}
CALLBACKS_MAPPER.registerCallback(toConsumer(MethodHandles.lookup(), annotated, method));