如何使用反射将 Lambda 表达式作为 JDK8 中的方法参数传递

Kin*_*ung 4 java reflection lambda

在 JDK 8 中,我可以使用反射来调用带有 FunctionInterface 参数的方法,并传递 Lambda 表达式。例如,这有效。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 5

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

\n\n
import java.lang.invoke.*;\nimport java.util.function.IntPredicate;  \nimport java.lang.reflect.Method;\n\npublic class LambdaReflect {\n\n    public static void main(String args[]) {\n        try {\n            for(Method m: LambdaReflect.class.getDeclaredMethods()) {\n                if(!m.getName().equals("test")) continue;\n                // we don\xe2\x80\x99t know the interface at compile-time:\n                Class<?> funcInterface=m.getParameterTypes()[0];\n                // but we have to know the signature to provide implementation code:\n                MethodType type=MethodType.methodType(boolean.class, int.class);\n                MethodHandles.Lookup l=MethodHandles.lookup();\n                MethodHandle target=l.findStatic(LambdaReflect.class, "lambda", type);\n                Object lambda=LambdaMetafactory.metafactory(l, "test",\n                    MethodType.methodType(funcInterface), type, target, type)\n                .getTarget().invoke();\n                boolean result = (Boolean) m.invoke(null, lambda);\n                System.out.println(result);\n                break;\n            }\n        } catch (Throwable ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    private static boolean lambda(int x) { return true; }\n\n    public static boolean test(IntPredicate func) {\n        return func.test(1);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

如果您想实现任意功能签名(这意味着实现相当简单,不依赖于未知参数),您可以使用MethodHandleProxies. 不同之处在于,MethodHandle不需要直接表示,即不需要表示真正的方法。因此,您可以创建一个始终返回常量的句柄,并用于dropArguments插入其他形式参数,直到您拥有一个具有正确功能签名的句柄,您可以将其传递给asInterfaceInstance

\n