Some basic questions about MethodHandle API

后端 未结 3 1930
攒了一身酷
攒了一身酷 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:40

    What is difference betweeen MethodHandle.invoke(), MethodHandle.invokeExact() and MethodHandle.invokeWithArguments()

    Since I also struggled with this, I decided to revisit this question and write an example that shows exactly what the semantic differences between these methods are.

    The major differences are:

    1. invokeExact only accepts exact arguments and return types, and does not accept arguments as an array. Calling e.g. method signature (Integer,Integer)Integer with an int argument is not allowed, but also calling it with an Object argument is not allowed, even if the object is actually of type Integer - the compiletime type of the argument must be of class Integer, not the runtime instance:

      Object arg = 1; Object[] args = {1,1};
      Integer i = (Integer)handle.invokeExact(1,1); // OK
      Object o = handle.invokeExact(arg,arg); // ERROR
      handle.invokeExact(args); // ERROR
      

    1. invoke automatically converts argument types and return types and also converts between primitive types and the corresponding wrapper classes. But it does also not accept arguments as an array. E.g. for method signature (Integer,Integer)Integer:

      Object arg = 1; Object[] args = {1,1};
      Integer i = (Integer)handle.invoke(1,1); // OK
      Object o = handle.invoke(arg,arg); // OK!
      o = handle.invoke(args); // ERROR
      

    1. invokeWithArguments removes all these restrictions and works very similar to Method#invoke - you can also supply an array (or a java.util.List) as an argument (but this flexibility comes with a huge performance penalty). E.g. for method signature (Integer,Integer)Integer:

      Object arg = 1; Object[] args = {1,1};
      Integer i = (Integer)handle.invokeWithArguments(1,1); // OK
      Object o = handle.invokeWithArguments(arg,arg); // OK
      o = handle.invokeWithArguments(args); // OK!
      

    Here a complete example:

    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodHandles;
    import java.lang.invoke.WrongMethodTypeException;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    public class MethodHandleTest {
    
        public static class TestClass{
            public int test(int a, Integer b){
                return a+b;
            }
        }
    
        public static void main(String[] args) throws Throwable{
            Method method = TestClass.class.getMethod("test", int.class, Integer.class);
            MethodHandle handle = MethodHandles.lookup().unreflect(method).bindTo(new TestClass());
    
            int arg_int = 1;
            Integer argInteger = 1;
    
            Object[] argArray = {1,1};
    
            //----------------------------
            // MethodHandle#invokeExact() 
            //----------------------------
    
            // ONLY an exact invocation is allowed for invokeExact:
            int result = (int) handle.invokeExact(arg_int, argInteger); 
    
            // inexact first argument type -> throws WrongMethodTypeException - "expected (int,Integer)int but found (Integer,Integer)int"
            Exception e = null;
            try {
                result = (int) handle.invokeExact(argInteger,argInteger);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            // inexact return type -> throws WrongMethodTypeException - "expected (int,Integer)int but found (int,Integer)Integer"
            try {
                result = (Integer) handle.invokeExact(arg_int,argInteger);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            // inexact return type -> throws WrongMethodTypeException - "expected (int,Integer)int but found (int,Integer)Object"
            try {
                Object o = handle.invokeExact(arg_int,argInteger);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            // "argObject" is ALSO NOT OK! - the compile time type of the argument must be of class Integer, not the runtime instance!
            // -> throws WrongMethodTypeException - "expected (int,Integer)int but found (int,Object)int"
            Object argObject = argInteger;
            try {
                result = (int) handle.invokeExact(arg_int,argObject);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            // Array of the arguments NOT allowed -> throws WrongMethodTypeException - "expected (int,Integer)int but found (Object[])int"
            try {
                result = (int) handle.invokeExact(argArray);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            // But explicit cast of first or second argument is OK
            result = (int) handle.invokeExact((int)argInteger,argInteger);
            result = (int) handle.invokeExact(arg_int,(Integer)arg_int);
    
            //-----------------------
            // MethodHandle#invoke() 
            //-----------------------
    
            // invoke() with exact types - OK -> actually calls invokeExact() behind the scenes
            result = (int) handle.invoke(arg_int, argInteger);
    
            // implicit conversion of inexact arguments and return type -> OK!
            result = (Integer) handle.invoke(argInteger,argInteger); 
    
            // Object arguments or return type is OK!
            Object o = handle.invoke(argObject,argObject);
    
            // Array of the arguments NOT allowed -> throws WrongMethodTypeException - "cannot convert MethodHandle(int,Integer)int to (Object[])int"
            try {
                result = (int) handle.invoke(argArray);
            } catch (WrongMethodTypeException ex) {
                e = ex;
            }
            assert e != null;
            e = null;
    
            //------------------------------------
            // MethodHandle#invokeWithArguments() 
            //------------------------------------
    
            // invoke() with exact types - OK
            result = (int) handle.invokeWithArguments(arg_int,arg_int);
    
            // implicit conversion of inexact arguments and return type -> OK
            result = (Integer) handle.invokeWithArguments(argInteger,argInteger); 
    
            // Object arguments or return type is OK!
            o = handle.invoke(argObject,argObject);
    
            // Array of the arguments -> OK
            result = (int) handle.invokeWithArguments(argArray);
    
            // List of arguments possible -> same as calling invokeWithArguments(list.toArray())
            result = (int) handle.invokeWithArguments(Arrays.asList(argArray));
    
    
        }
    }
    

提交回复
热议问题