Java MethodHandle.invokeExact()抛出WrongMethodTypeException问题排查
问题解析:MethodHandle invokeExact 抛出 WrongMethodTypeException 的原因
异常信息含义
报错信息java.lang.invoke.WrongMethodTypeException: expected (FooImpl)CompletableFuture but found (Foo)CompletableFuture的核心意思是:
- 你获取到的MethodHandle,方法签名要求传入的参数必须是FooImpl类型(也就是该方法所属的具体实现类)
- 但你实际传入的参数是Foo接口类型,invokeExact要求参数类型在字节码层面完全匹配,哪怕是父类/接口都不兼容,因此触发类型不匹配异常。
深层原因
- MethodHandle的签名绑定逻辑:你通过
foo.getClass()拿到的是FooImpl的Class对象,调用getDeclaredMethods获取的barMethod是FooImpl类中实现的bar方法。当用unreflect将Method转为MethodHandle时,该Handle的签名会严格绑定到FooImpl实例——因为底层字节码方法属于FooImpl,它的调用者类型被硬编码为FooImpl。 - invokeExact的绝对严格性:invokeExact是“精确调用”,不会做任何类型适配:既不会自动把接口类型引用转成实现类类型,也不兼容父类/接口参数类型。哪怕foo变量实际指向FooImpl对象,但编译时传入的是Foo类型,invokeExact就会判定类型不匹配。
- invoke能正常执行的原因:invoke方法会自动做类型适配,比如检查实际对象类型并完成Foo到FooImpl的转换,因此不会触发异常。
解决办法
有两种可行的修复方式:
- 强制转换参数类型:调用invokeExact时把foo强制转为FooImpl:
CompletableFuture<?> result = (CompletableFuture<?>)methodHandle.invokeExact((FooImpl)foo); - 适配MethodHandle的签名:如果无法确定实现类类型,用
asType修改Handle签名,让它接受Foo类型参数:MethodHandle adaptedHandle = methodHandle.asType(MethodType.methodType(CompletableFuture.class, Foo.class)); CompletableFuture<?> result = (CompletableFuture<?>)adaptedHandle.invokeExact(foo);
内容的提问来源于stack exchange,提问作者Garret Wilson
相关产品推荐
相关产品推荐

