MethodHandle.invokeExact() 出现 WrongMethodTypeException,但没有参数且返回类型相同

问题描述 投票:0回答:1

我在 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
这样的东西了?为什么它们会不同?
    

java reflection methodhandle
1个回答
0
投票
(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

© www.soinside.com 2019 - 2024. All rights reserved.