Java7为间接调用方法引入了新的API。其中的关键是java.lang.invoke包,即方法句柄。你可以把它看做反射的现代化方式,但它不像反射API那样有时会显得冗长、繁重和粗糙。方法句柄是将invokedynamic引入JVM项目中的一部分。
什么是Method Handle?它是对可直接执行的方法(或域、构造方法等)的类型化引用。还有一种说法是,方法句柄是一个有能力安全调用方法的对象。
MethodType type():Reports the type of this method handle.
Object invoke(Object... args):Invokes the method handle, allowing any caller type descriptor,
and optionally performing conversions on arguments and return values.
Object invokeExact(Object... args):Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
Object invokeWithArguments(Object... arguments):Performs a variable arity invocation, passing the arguments in the given list to the method handle, as if via an inexact invoke from a call site which mentions only the type Object, and whose arity is the length of the argument list.
Object invokeWithArguments(java.util.List> arguments):Performs a variable arity invocation, passing the arguments in the given array to the method handle, as if via an inexact invoke from a call site which mentions only the type Object, and whose arity is the length of the argument array.
MethodHandle bindTo(Object x):Binds a value x to the first argument of a method handle, without invoking it.
MethodTYpe是表示方法签名类型的不可变对象。每个方法句柄都有一个MethodType实例,用来指明方法的返回类型和参数类型。但它没有方法的名字和“接收者类型”,即调用的实例方法的类型。
要从lookup对象中得到方法句柄,你需要给出持有所需方法的类、方法的名称,以及跟你所需的方法签名相匹配的MethodType。
MethodHandles.Lookup lookup = MethodHandles.lookup();
lookup.findXxx方法提供了各种查找方式
MethodHandle findVirtual(Class> refc, String name, MethodType type):Produces a method handle for a virtual method.
The type of the method handle will be that of the method, with the receiver type refc prepended.
The method and all its argument types must be accessible to the lookup object.
Object rValue = methodHandle.invokeXxx(...)。
Object x, y; String s; int i;
MethodType mt; MethodHandle mh;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// mt is (char,char)String
mt = MethodType.methodType(String.class, char.class, char.class);
mh = lookup.findVirtual(String.class, "replace", mt);
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
assertEquals(s, "nanny");
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
assertEquals(s, "savvy");
// mt is (Object[])List
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList("one","two"));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assertEquals(x, java.util.Arrays.asList(1,2,3));
// mt is ()int
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
// invokeExact(Ljava/util/List;)I
assert(i == 3);
mt = MethodType.methodType(void.class, String.class);
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V