invoke - JiyangM/spring GitHub Wiki

java7中为间接调用方法引入了新的api,即 方法句柄

方法句柄中包含两个重要的类,MethodHandle和MethodType

  • MethodHandle

通过句柄我们可以直接调用该句柄所引用的底层方法。从作用上来看,方法句柄类似于反射中的Method类,是对要执行的方法的一个引用,我们也是通过它来调用底层方法,它调用时有两个方法 invoke和invokeExact,后者要求参数类型与底层方法的参数完全匹配,前者则在有出入时做修改如包装类型。

  • MethodType

方法签名不可变对象,是对方法的一个映射,包含返回值和参数类型。在lookup时也是通过它来寻找的。 每个方法句柄都有一个MethodType实例,用来指明方法的返回类型和参数类型。

demo:

public class MethodHandleDemo {

    public static void main(String[] args) throws Throwable{
        //参数为返回值类型、参数类型  单个参数
        MethodType methodType = MethodType.methodType(void.class, String.class);
        //声明定义方法句柄,通过lookup对象得到方法句柄,参数为方法所在的类、方法的名称、所匹配的方法签名
        MethodHandle methodHandle = MethodHandles.lookup().findVirtual(Test.class, "testMethod", methodType);
        //调用底层方法
        methodHandle.invoke(Test.class.newInstance(), "hello, world");
        //多个参数
        MethodHandle testMethod = MethodHandles.lookup().findVirtual(Test.class, "testMethod", MethodType.methodType(Object.class, String.class, int.class));
        testMethod.invoke(Test.class.newInstance(), "aa", 1);

        MethodType f3 = MethodType.methodType(Object.class, int.class, int.class);

        //查找静态方法
        MethodHandle aStatic = MethodHandles.lookup().findStatic(Test.class, "add", f3);

        //使用invokeExact调用时,参数类型和返回值类型必须与方法签名的一致
        aStatic.invokeExact(1, 1234);

        //调用静态方法 无法调用private的方法
        //aStatic.invoke( 1, 3);

    }

}
class Test {

    public void testMethod(String str) {
        System.out.println("testMethod : "+str);
    }

    public Object testMethod(String str, int x) {
        System.out.println("string = " + str+ " , int = " + x);
        return x;
    }

   /*private*/ public static Object add(int a, int b) {
        System.out.println("a + b = " + (a + b));
        return a + b;
    }
}
  • 同反射的区别:

    • 效率上比反射高
    • 轻量级