如何使用Object 数组调用MethodHandle.invokeExact()?
Java的MethodHandle.invokeExact(Object … args)采用可变长度的参数列表。 但是当我尝试传递一个Object []数组而不是一个列表时,我收到一个错误。 见下文:
private void doIt() throws Throwable { Method meth = Foo.class.getDeclaredMethods()[0]; MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle mh = lookup.unreflect(meth); Foo foo = new Foo(); String myStr = "aaa"; Integer myInt = new Integer(10); Object [] myArray = {foo, myStr, myInt}; mh.invokeExact(foo, myStr, myInt); // prints "Called aaa 10" mh.invokeExact(myArray); // throws Exception } class Foo { public void bar(String myStr, Integer myInt) { System.out.println("Called " + myStr + " " + myInt); } }
第二次调用invokeExact()会产生以下exception:
Exception in thread "main" java.lang.invoke.WrongMethodTypeException: (Ljava/lang/String;Ljava/lang/Integer;)V cannot be called with a different arity as ([Ljava/lang/Object;)V at io.rhubarb.core.TestInvoke.doIt0(TestInvoke.java:26) at io.rhubarb.core.TestInvoke.main(TestInvoke.java:11)
这可能与两年前修复的Eclipse中的错误有关( https://bugs.eclipse.org/bugs/show_bug.cgi?id=385404 ),但我不这么认为,因为当我关闭Eclipse时,删除/ target目录,使用Maven重新编译所有内容,并从命令行运行,我得到相同的结果。
我正在使用Eclipse Kepler SR2,一切都是最新的,JDK 1.7.0_25。
MethodHandle.invoke()
和MethodHandle.invokeExact()
是不像其他变量arity方法那样运行的特殊方法:
与通常的虚方法一样,源级调用
invokeExact
并invoke
compile到invokeExact
指令。 更不寻常的是, 编译器必须记录实际的参数类型,并且可能不会对参数执行方法调用转换 。 相反,它必须根据自己未转换的类型将它们推入堆栈。 方法句柄对象本身在参数之前被压入堆栈。 然后,编译器使用符号类型描述符调用方法句柄,该描述符描述参数和返回类型。
因此,当您调用这些方法时,参数类型真的很重要。 如果要将参数作为Object[]
传递,则应使用invokeWithArguments()
代替:
mh.invokeWithArguments(myArray);
也可以看看:
-
MethodHandle
javadoc