反射(Reflect)作為Java最重要的一種機制,相信大家一定都很熟悉了,今天要介紹另一種和反射機制類似的方法調(diào)用機制——MethodHandle。
MethodHandle是Java7引入的一種機制,主要是為了JVM支持動態(tài)語言。
一個MethodHandle調(diào)用示例
首先,讓指北君給大家演示一下最基本的MethodHandle使用。
第一步:創(chuàng)建查找對象:Lookup
// 獲取Look用于查找方法句柄
MethodHandles.Lookup lookup = MethodHandles.lookup();
第二步:創(chuàng)建方法類型:MethodType
構(gòu)造方法的返回值類型,參數(shù)類型
// 方法類型,描述返回值和參數(shù),第一個參數(shù)為返回值類型,void則為void.class。第二個參數(shù)開始為被調(diào)用方法的參數(shù)類型
MethodType mt = MethodType.methodType(boolean.class, String.class, int.class);
第三步:查找方法句柄
Lookup的findVirtual查找成員方法
//查找方法句柄,參數(shù)1:調(diào)用類,參數(shù)2:方法名,參數(shù)3:方法類型
MethodHandle handle = lookup.findVirtual(String.class, "startsWith", mt);
第四步:方法調(diào)用
通過MehodHandle的invoke方法執(zhí)行,并返回結(jié)果
//方法調(diào)用,參數(shù)1:實例,參數(shù)2..n:方法參數(shù)
Boolean value = (Boolean)handle.invoke("the i am in the room", "the", 0);
以上就是一個簡單的調(diào)用示例。
核心代碼解讀
上面我們展示了一個最進本MethodHandle方式的方法調(diào)用,下面我們將對其中用到的主要類進行介紹。這些主要的類包含MethodType,MethodHandle,MethodHandles及Lookup。
MethodType
首先,我們來看看Methodtype,MethodType是用來封裝方法輸入輸出類型的,包含方法的返回和方法的參數(shù)。MethodType構(gòu)造方法為私有,只能通過MethodType提供的靜態(tài)工具方法來獲取實例
/**
* Constructor that performs no copying or validation.
* Should only be called from the factory method makeImpl
*/
private MethodType(Class< ? > rtype, Class< ? >[] ptypes) {
this.rtype = rtype;
this.ptypes = ptypes;
}
MethodType中常用的工具方法有:
- 大于一個參數(shù)
public static MethodType methodType(Class< ? > rtype, Class< ? > ptype0, Class< ? >... ptypes) {
Class< ? >[] ptypes1 = new Class< ? >[1+ptypes.length];
ptypes1[0] = ptype0;
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
return makeImpl(rtype, ptypes1, true);
}
- 無參數(shù)
public static MethodType methodType(Class< ? > rtype) {
return makeImpl(rtype, NO_PTYPES, true);
}
工具方法都通過makeImple方法來封裝MethodType實例,指北君帶領(lǐng)大家來看看makeImple中做了哪些事情:
- 參數(shù)檢查
- 返回值的類型不能為null,如果無返回使用void.class
- 參數(shù)類型不能為null,且不能為void.class
- 使用緩存表緩存MethodType實例,優(yōu)化處理
- 如果非信任模式(trusted==false),則克隆參數(shù)數(shù)組
這里需要注意MethodType重寫了hashCode方法,從邏輯看參數(shù)數(shù)組克隆不影響同類型的緩存機制。
static
MethodType makeImpl(Class< ? > rtype, Class< ? >[] ptypes, boolean trusted) {
if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
MethodType primordialMT = new MethodType(rtype, ptypes);
MethodType mt = internTable.get(primordialMT);
if (mt != null)
return mt;
// promote the object to the Real Thing, and reprobe
MethodType.checkRtype(rtype);
if (trusted) {
MethodType.checkPtypes(ptypes);
mt = primordialMT;
} else {
// Make defensive copy then validate
ptypes = Arrays.copyOf(ptypes, ptypes.length);
MethodType.checkPtypes(ptypes);
mt = new MethodType(rtype, ptypes);
}
mt.form = MethodTypeForm.findForm(mt);
return internTable.add(mt);
}
除了靜態(tài)工具方法外,MethodType還有幾個實例方法,主要為差異性較小的MethodType提供快速獲取實例的方法。包含:
- changeParameterType
- insertParameterTypes
- appendParameterTypes
- dropParameterTypes
MethodHandle
MethodHandle為抽象類,但是里面提供了大量的原生方法,提供底層訪問,也是方法調(diào)用的核心邏輯。這部分涉及MethodHandle的機制實現(xiàn),對于使用功能來說指北君就不在此展開了。
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
調(diào)用方法
MethodHandles, Lookup
MethodHandles不是MethodHandle的實現(xiàn),他提供工具用于幫助獲取MethodHandle,我們主要使用到lookup(),publicLookup()
@CallerSensitive注解,可以使Reflection.getCallerClass()獲取到調(diào)用lookup()方法的類
@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
public static Lookup lookup() {
return new Lookup(Reflection.getCallerClass());
}
public static Lookup publicLookup() {
return Lookup.PUBLIC_LOOKUP;
}
Lookup構(gòu)造方法主要傳入兩個參數(shù):
- lookupClass搜尋的類,
- allowedModes:許可模式。
最后,通過Lookup的findXXX獲取到MethodHandle,詳細說明見下表:
查找方法
小結(jié)
關(guān)于MethodHandle的基本使用就基本講完,這里附上一張類圖便大家理解:
-
參數(shù)
+關(guān)注
關(guān)注
11文章
1737瀏覽量
31994 -
代碼
+關(guān)注
關(guān)注
30文章
4701瀏覽量
68124 -
Method
+關(guān)注
關(guān)注
0文章
8瀏覽量
7244 -
JVM
+關(guān)注
關(guān)注
0文章
157瀏覽量
12189
發(fā)布評論請先 登錄
相關(guān)推薦
評論