我正在尝试使用 JavaLambdaMetaFactory
来动态实现通用 lambda Handler<RoutingContext>
,:
public class RoutingContext {
// ...
}
@FunctionalInterface
public interface Handler<X> {
public void handle(X arg);
}
public class HomeHandler extends Handler<RoutingContext> {
@Override
public void handle(RoutingContext ctx) {
// ...
}
}
这是我的尝试LambdaMetaFactory
:
try {
Class<?> homeHandlerClass = HomeHandler.class;
Method method = homeHandlerClass.getDeclaredMethod(
"handle", RoutingContext.class);
Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(method);
MethodType factoryMethodType = MethodType.methodType(Handler.class);
MethodType functionMethodType = mh.type();
MethodHandle implementationMethodHandle = mh;
Handler<RoutingContext> lambda =
(Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup,
"handle",
factoryMethodType,
functionMethodType,
implementationMethodHandle,
implementationMethodHandle.type())
.getTarget()
.invokeExact();
lambda.handle(ctx);
} catch (Throwable e) {
e.printStackTrace();
}
这给出了错误:
java.lang.AbstractMethodError: Receiver class [...]$$Lambda$82/0x00000008001fa840
does not define or inherit an implementation of the resolved method abstract
handle(Ljava/lang/Object;)V of interface io.vertx.core.Handler.
functionMethodType
我已经为and尝试了一系列其他选项implementationMethodHandle
,但还没有设法让它工作。此外,即使我将RoutingContext.class
引用替换为Object.class
,这也不能修复错误。
我可以使lambda.handle(ctx)
调用成功的唯一方法是通过更改HomeHandler
使其不扩展Handler
,使其成为HomeHandler::handle
静态并更改RoutingContext.class
为Object.class
. 奇怪的是,我仍然可以将生成的 lambda 转换为Handler<RoutingContext>
,即使它不再扩展Handler
。
我的问题:
如何
LambdaMetaFactory
使用非静态方法?对于这个非静态 SAM 类
HomeHandler
,它如何在后台使用实例分配?是否LambdaMetaFactory
创建接口实现的单个实例,无论有多少方法调用,因为在此示例中没有捕获的变量?或者它是否为每个方法调用创建一个新实例?还是我应该创建一个实例并以某种方式将其传递给 API?如何
LambdaMetaFactory
使用泛型方法?
编辑:除了下面的好答案之外,我还看到了这篇博客文章,解释了所涉及的机制:
https://medium.freecodecamp.org/a-faster-alternative-to-java-reflection-db6b1e48c33e