9

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 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。

4

1 回答 1

14

MethodHandle.invoke()并且MethodHandle.invokeExact()是与其他可变参数方法不同的特殊方法:

与虚拟方法一样,源级调用invokeExactinvoke编译为invokevirtual指令。更不寻常的是,编译器必须记录实际的参数类型,并且可能不对参数进行方法调用转换。相反,它必须根据它们自己未转换的类型将它们压入堆栈。方法句柄对象本身在参数之前被压入堆栈。然后编译器使用描述参数和返回类型的符号类型描述符调用方法句柄。

所以,当你调用这些方法时,参数的类型真的很重要。如果要将参数作为 传递Object[],则应invokeWithArguments()改为使用:

mh.invokeWithArguments(myArray);

也可以看看:

于 2014-05-02T18:55:45.273 回答