簡介
java7在JSR 292中增加了對動態類型語言的支持,使java也可以像C語言那樣將方法作爲參數傳遞,其實現在lava.lang.invoke包中。MethodHandle作用類似於反射中的Method類,但它比Method類要更加靈活和輕量級。通過MethodHandle進行方法調用一般需要以下幾步:
(1)創建MethodType對象,指定方法的簽名;
(2)在MethodHandles.Lookup中查找類型爲MethodType的MethodHandle;
(3)傳入方法參數並調用MethodHandle.invoke或者MethodHandle.invokeExact方法。
MethodType
可以通過MethodHandle類的type方法查看其類型,返回值是MethodType類的對象。也可以在得到MethodType對象之後,調用MethodHandle.asType(mt)方法適配得到MethodHandle對象。可以通過調用MethodType的靜態方法創建MethodType實例,有三種創建方式:
(1)methodType及其重載方法:需要指定返回值類型以及0到多個參數;
(2)genericMethodType:需要指定參數的個數,類型都爲Object;
(3)fromMethodDescriptorString:通過方法描述來創建。
創建好MethodType對象後,還可以對其進行修改,MethodType類中提供了一系列的修改方法,比如:changeParameterType、changeReturnType等。
Lookup
MethodHandle.Lookup相當於MethodHandle工廠類,通過findxxx方法可以得到相應的MethodHandle,還可以配合反射API創建MethodHandle,對應的方法有unreflect、unreflectSpecial等。
invoke
在得到MethodHandle後就可以進行方法調用了,有三種調用形式:
(1)invokeExact:調用此方法與直接調用底層方法一樣,需要做到參數類型精確匹配;
(2)invoke:參數類型鬆散匹配,通過asType自動適配;
(3)invokeWithArguments:直接通過方法參數來調用。其實現是先通過genericMethodType方法得到MethodType,再通過MethodHandle的asType轉換後得到一個新的MethodHandle,最後通過新MethodHandle的invokeExact方法來完成調用。
附MethodHandle作爲參數的示例代碼:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.List;
public class MethodHandleTest {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findStatic(MethodHandleTest.class, "doubleVal", MethodType.methodType(int.class, int.class));
List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5);
MethodHandleTest.transform(dataList, mh);// 方法做爲參數
for (Integer data : dataList) {
System.out.println(data);//2,4,6,8,10
}
}
public static List<Integer> transform(List<Integer> dataList, MethodHandle handle) throws Throwable {
for (int i = 0; i < dataList.size(); i++) {
dataList.set(i, (Integer) handle.invoke(dataList.get(i)));//invoke
}
return dataList;
}
public static int doubleVal(int val) {
return val * 2;
}
}