如何用Object []数组调用MethodHandle.invokeExact()?

问题描述:

Java的MethodHandle.invokeExact(Object ... args)采用可变长度的参数列表.但是,当我尝试传递Object []数组而不是列表时,出现错误.见下文:

Java's MethodHandle.invokeExact(Object...args) takes a variable-length list of arguments. When I try to pass an array of Object [] instead of a list, though, I get an error. See below:

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()会产生此异常:

The second call to invokeExact() produces this 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重新编译所有内容,然后从命令行运行我得到相同的结果.

This might be related to a bug in Eclipse that was fixed two years ago (https://bugs.eclipse.org/bugs/show_bug.cgi?id=385404) but I don't think so, because when I close Eclipse, delete the /target directory, recompile everything using Maven, and run from the command line I get the same results.

我正在使用Eclipse Kepler SR2,所有内容都是最新的,以及JDK 1.7.0_25.

I'm using Eclipse Kepler SR2, everything fully up to date, and JDK 1.7.0_25.

MethodHandle.invoke()MethodHandle.invokeExact()是特殊方法,其行为与其他可变arity方法不同:

MethodHandle.invoke() and MethodHandle.invokeExact() are special methods that don't behave like other variable arity methods:

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

As is usual with virtual methods, source-level calls to invokeExact and invoke compile to an invokevirtual instruction. More unusually, the compiler must record the actual argument types, and may not perform method invocation conversions on the arguments. Instead, it must push them on the stack according to their own unconverted types. The method handle object itself is pushed on the stack before the arguments. The compiler then calls the method handle with a symbolic type descriptor which describes the argument and return types.

因此,当您调用这些方法时,参数的类型确实很重要.如果要将参数作为Object[]传递,则应改用invokeWithArguments():

So, types of parameters really matter when you call these methods. If you want to pass parameters as Object[], you should use invokeWithArguments() instead:

mh.invokeWithArguments(myArray);

另请参见:

  • MethodHandle javadoc