一.總述
java7為間接調用方法提供了MethodHandle類,即方法句柄。可以將其看作是反射的另一種方式。這是使用MethodHandle調用方法的一個例子:
public class Test {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(String.class,char.class,char.class);
try {
MethodHandle mh = lookup.findVirtual(String.class,"replace", mt);
String handled_str = (String) mh.invoke("abc",'a','c');
System.out.print(handled_str);
} catch (NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
用MethodHandle調用方法的流程為:
- (1) 創建MethodType,獲取指定方法的簽名
- (2) 在Lookup中查找MethodType的方法句柄MethodHandle
- (3) 傳入方法參數通過MethodHandle調用方法
二.MethodType
MethodType表示一個方法類型的對象,每個MethodHandle都有一個MethodType實例,MethodType用來指明方法的返回類型和參數類型。其有多個工廠方法的重載。static MethodType methodType(Class<?> rtype)
static MethodType methodType(Class<?> rtype, Class<?> ptype0)
static MethodType methodType(Class<?> rtype, Class<?>[] ptypes)
static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes)
static MethodType methodType(Class<?> rtype, List<Class<?>> ptypes)
static MethodType methodType(Class<?> rtype, MethodType ptypes)
如上面示例代碼中的
MethodType mt = MethodType.methodType(String.class,char.class,char.class);
就得到了一個方法的參數類型為char,char,返回類型為String的MethodType。
三.Lookup
MethodHandle.Lookup可以通過相應的findxxx方法得到相應的MethodHandle,相當於MethodHandle的工廠方法。查找對象上的工廠方法對應於方法、構造函數和字段的所有主要用例。下面是官方API文檔對findxxx的說明,這些工廠方法和結果方法處理的行為之間的對應關系:可以看出findStatic
相當於得到的是一個static方法的句柄,findVirtual
找的是普通方法。其他的可以從官方文檔中閱讀得知,這里不詳細說明了。
四. MethodHandle
MethodHandle是什么?簡單的說就是方法句柄,通過這個句柄可以調用相應的方法。官方文檔對其的解釋為:“ A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values. These transformations are quite general, and include such patterns as conversion, insertion, deletion, and substitution.”
翻譯如下:
方法句柄是對底層方法、構造函數、字段或類似低級操作的類型化、直接可執行的引用,具有參數或返回值的可選轉換。這些轉換非常普遍,包括轉換、插入、刪除和替換等模式
常用的方法為invokexxx,如下圖
其中需要注意的是invoke
和invokeExact
,前者在調用的時候可以進行返回值和參數的類型轉換工作,而后者是精確匹配的。比如,在MethodType中指定的參數類型是int
,如果你用invoke
調用時指定的參數是Integer
類型,方法調用是可以運行的,這是通過MethodHandle
類的astype
方法產生一個新的方法句柄。而如果用的是invokeExact
則在運行時會報錯。
另外一個需要注意的是invokexxx的所有方法返回的是Object
,調用時若有返回結果一般需進行強制類型轉換。
最后還有一點,如果調用的方法沒有返回值,那么在MethodType
的工廠方法中的返回值類型寫為void.class