Как получить лямбда-выражение из метода Java - PullRequest
0 голосов
/ 20 мая 2018

Предположим, у меня есть следующий метод:

void test () {...}

Я получаю этот метод с помощью отражения, но его вызов будет очень медленным, поэтому я хочу получить из него Runnable, как будто я напишу

this::test

Есть ли способ добиться этого?

1 Ответ

0 голосов
/ 20 мая 2018

Мне нужна реализация для метода, подобного этому: 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, который вы передаете этому, должен быть создан в том же модуле, что и метод, к которому вы пытаетесь получить доступ.(короче говоря, у дескрипторов методов есть еще несколько ограничений доступа).Но если метод и класс, к которому вы пытаетесь получить доступ, являются общедоступными, тогда проблем нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...