首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在带有反射的JDK8中将Lambda表达式作为方法参数传递

如何在带有反射的JDK8中将Lambda表达式作为方法参数传递
EN

Stack Overflow用户
提问于 2014-12-20 03:50:00
回答 2查看 2.1K关注 0票数 3

在JDK8中,我可以使用反射来调用带有FunctionalInterface参数的方法,传递一个Lambda表达式。例如,这是可行的。

代码语言:javascript
复制
import java.util.function.IntPredicate;  
import java.lang.reflect.Method;

public class LambdaReflect {

    public static void main(String args[]) {
        System.out.println(test(x->true));
        // Now do this in reflection
        Class<LambdaReflect> thisC = LambdaReflect.class;
        Method meths[] = thisC.getDeclaredMethods();
        Method m = meths[1];  // test method
        try {
            IntPredicate lamb = x->true;
            boolean result = (Boolean) m.invoke(null, lamb);
            System.out.println(result);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static boolean test(IntPredicate func) {
        return func.test(1);
    }
}

但是,如果参数类型仅在运行时已知,我如何将lambda表达式传递给该方法?换句话说,如果我在编译时不知道方法的参数类型,但只知道它是一个函数接口,我可以使用反射通过lambda表达式调用它吗?

EN

回答 2

Stack Overflow用户

发布于 2014-12-20 05:19:46

如果不知道编译时的目标类型,就不能创建lambda表达式。但是您可以将lambda的代码放入一个方法中,并创建对此方法的方法引用。这类似于lambda表达式的编译方式。不同之处在于函数接口实现是使用反射代码显式创建的:

代码语言:javascript
复制
import java.lang.invoke.*;
import java.util.function.IntPredicate;  
import java.lang.reflect.Method;

public class LambdaReflect {

    public static void main(String args[]) {
        try {
            for(Method m: LambdaReflect.class.getDeclaredMethods()) {
                if(!m.getName().equals("test")) continue;
                // we don’t know the interface at compile-time:
                Class<?> funcInterface=m.getParameterTypes()[0];
                // but we have to know the signature to provide implementation code:
                MethodType type=MethodType.methodType(boolean.class, int.class);
                MethodHandles.Lookup l=MethodHandles.lookup();
                MethodHandle target=l.findStatic(LambdaReflect.class, "lambda", type);
                Object lambda=LambdaMetafactory.metafactory(l, "test",
                    MethodType.methodType(funcInterface), type, target, type)
                .getTarget().invoke();
                boolean result = (Boolean) m.invoke(null, lambda);
                System.out.println(result);
                break;
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
    }

    private static boolean lambda(int x) { return true; }

    public static boolean test(IntPredicate func) {
        return func.test(1);
    }
}

如果您想实现任意的函数签名(这意味着实现相当简单,不依赖于未知参数),您可以使用MethodHandleProxies。不同的是,MethodHandle不需要是直接的,也就是说,不需要表示真正的方法。因此,您可以创建一个handle invariably returning a constant并使用dropArguments插入其他形式参数,直到您有了可以传递给asInterfaceInstance的正确函数签名的句柄

票数 4
EN

Stack Overflow用户

发布于 2014-12-20 04:27:08

您总是可以通过使用允许编译器推断函数接口的类型转换来指示lambda表达式:

代码语言:javascript
复制
m.invoke(null, (IntPredicate) (x -> true));

但是,如果您对签名如此了解,为什么还要使用反射呢?如果要生成接口的运行时实现,则应使用运行时生成的类来实现该接口。在Java代理或我的库Byte Buddy中查找它。这样,您可以按如下方式提供参数:

代码语言:javascript
复制
IntPredicate instance = new ByteBuddy()
  .subclass(IntPredicate.class)
  .method(named("test")).intercept(FixedValue.value(true));
  .make()
  .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
  .getLoadedClass()
  .newInstance();
 m.invoke(null, instance);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27572966

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档