Some basic questions about MethodHandle API

后端 未结 3 1927
攒了一身酷
攒了一身酷 2020-12-13 05:02

How can I obtain all declared method through MethodHandles.lookup()? How can I obtain all declared fields?

What is difference betweeen MethodHandl

3条回答
  •  一向
    一向 (楼主)
    2020-12-13 05:45

    As Balder said both calls invoke and invokeExact do not accept arguments passed in as an array. (However, they do accept array arguments.)

    int[] args = {1,1};
    
    // handle for Math.addExact(int, int)
    Object o = handle.invokeExact(1,1); // OK
    Object o = handle.invoke(1,1); // OK
    Object o = handle.invokeExact(args); // ERROR
    Object o = handle.invoke(args); // ERROR
    

    The error is always a wrong type exception:

    java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(int, int)int to (Object[])int
    

    So it does not unpack the array. But passing in an array where it is required works:

    // handle for Arrays.sort(int[]) 
    handle.invokeExact(args); // OK
    handle.invoke(args); // OK
    

    As Balder said, implementing the desired behavior with invokeWithArguments() may incur a quite substantial overhead.

    In order to get the desired behavior for unpacking argument lists as known from varargs, one has to turn the handle into a spreader:

     // handle for Math.addExact(int, int)
     handle = handle.asSpreader(int[].class, 2);
     handle.invokeExact(args); // OK
     handle.invoke(args); // OK
    

    Of course, the same functionality as for explicit argument passing accounts again when the array is defined to be generic:

     Object[] args = new Object[]{1,1};
     // handle for Math.addExact(int, int)
     handle = handle.asSpreader(int[].class, 2);
     handle.invokeExact(args); // ERROR
     handle.invoke(args); // OK
    

    I have not conducted any performance comparison between the calls. For those interested, it is quite straight forward to extend this benchmark: http://rick-hightower.blogspot.de/2013/10/java-invoke-dynamic-examples-java-7.html

    Details:

    Essentially invokeWithArguments does similar things but does so for every call:

     public Object invokeWithArguments(Object... arguments) throws Throwable {
        MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
        return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
    }
    

    So creating a spreader once and reusing it, will most likely yield similar performance as invoke and invokeExact.

提交回复
热议问题