我在 AWS Lambda 上使用 Java 17。我有一个接口
Foo
,带有方法 bar()
,返回 CompletableFuture<Map<Bar, Long>>
:
public interface Foo {
public CompletableFuture<Map<Bar, Long>> bar();
}
在
MyProcessor
类中,我有一个对 Foo
实现的实例引用,即 FooImpl
:
class MyProcessor {
private final Foo foo;
MyProcessor() {
foo = goGetFooImpl();
}
void doSomething() {
…
}
}
最后在
MyProcessor.doSomething()
中,我查找 Foo.bar()
方法并尝试使用方法句柄调用它(为了清楚起见,省略了异常处理):
//filter out the only method with the name "bar"
Method barMethod = foo.getClass().getDeclaredMethods().…;
MethodHandle = MethodHandles.lookup().unreflect(barMethod);
CompletableFuture<?> result = (CompletableFuture<?>)methodHandle.invokeExact(foo);
错误消息很奇怪:
java.lang.invoke.WrongMethodTypeException: expected (FooImpl)CompletableFuture but found (Foo)CompletableFuture
我意识到参数和返回类型必须准确。在这种情况下,没有任何争论。据我了解,
MethodHandle.invokeExact()
的泛型类型会在运行时被删除;因此在这种情况下,具体返回类型是相同的。那么问题出在哪里呢?错误消息中提到 CompletableFuture
和
(Fooimpl)
是什么意思?目标类型如何影响 (Foo)
的类型?我意识到 CompletableFuture
方法是在
bar()
上声明的,但是在 Foo
实例的类上查找该方法。但为什么这会成为一个问题呢?从文档中我了解到 FooImpl
适用于虚拟方法。我可以在这里调用 MethodHandle.invokeExact()
,效果很好,但不行
methodHandle.invoke(foo)
。我正在做的事情有什么不“准确”的地方?有谁知道错误消息是什么意思?我发现 MethodHandle 强制转换返回类型 这似乎是相关的,但我仍然没有得到它。 methodHandle.invokeExact(foo)
是
CompletableFuture
。从什么时候开始有CompletableFuture
和(Foo)CompletableFuture
这样的东西了?为什么它们会不同?(FooImpl)CompletableFuture
实际上意味着参数的静态类型必须与 MethodHandle 的类型完全匹配。
invokeExact
和 Foo
不是同一类型。另请参阅 FooImpl
的文档:invokeExact 调用点的符号类型描述符必须 与该方法句柄的类型完全匹配。不允许进行任何转换 参数或返回值。
invokeExact
的符号描述符是从调用站点的参数和返回值的静态类型派生的。在您的情况下,即
invokeExact
,采用 1 个类型为 (Foo)CompletableFuture
的参数并返回 Foo
(您还可以使用 CompletableFuture
检查类型描述符来反汇编类文件)。另请参阅有关签名多态性的文档部分:https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/invoke/MethodHandle.html#sigpoly
javap
自动应用从
invoke
到 Foo
的类型转换,这样就可以了。如果您仅使用 FooImpl
调用 MethodHandle 一次就可以了。如果您打算多次调用它,您可以将接收器的类型删除为
invoke
以避免类型转换:Foo