如何从Java方法获取lambda表达式

时间:2018-05-19 22:52:28

标签: java reflection lambda

假设我有以下方法:

void test () {...}

我通过反射得到这个方法,但是调用它会非常慢,所以我想从中获取Runnable,好像我会写一样

this::test

有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:1)

  

我需要一个像这样的方法的实现:Runnable toRunnable(Method method);所以我们得到一个Method,我们需要返回Runnable

这与this::test不完全相同,因为它也使用this实例进行绑定,因此您还必须传递要绑定的实例。但是,您可以使用方法句柄,这是this::test

之类的基础实现

有这样的课程:

public class MyClass {
    public void test() { 
        System.out.println("Test Called");
    }
}

您可以创建此方法:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;

...

public static Runnable toRunnable(Method method, Object instance) throws ReflectiveOperationException {
    Lookup lookup = lookup();

    MethodHandle test = lookup.unreflect(method);       
    try {
        return (Runnable) LambdaMetafactory.metafactory(
            lookup,
            "run",
            methodType(Runnable.class, instance.getClass()),
            methodType(void.class),
            test,
            methodType(void.class)
        ).getTarget().invoke(instance);
    } catch (Throwable e) {
        throw new RuntimeException("Should not occur", e);
    }
}

并称之为:

Object ref = new MyClass(); // get from somewhere

Runnable result = toRunnable(ref.getClass().getMethod("test"), ref);
result.run(); // prints 'Test Called'

需要注意的是,test方法必须可以从您调用lookup()的位置访问,您可以通过将Lookup传递给方法来解决此问题手动,并在您可以访问test方法的位置创建它。或者,如果您使用的是Java 9,则可以使用privateLookup(Class<?>, Lookup),但是传递给它的Lookup需要在与您尝试访问的方法相同的模块中创建。 (简而言之,方法句柄对它有一些访问限制)。但是,如果您尝试访问的方法和类可以公开访问,那么就没有问题了。