Java MethodHandle的使用詳解
Java MethodHandle的使用
Java中的MethodHandle是Java SE 7中引入的一種新的機(jī)制,用于動(dòng)態(tài)調(diào)用方法。
以下是對(duì)Java MethodHandle的詳細(xì)解釋:
定義
- MethodHandle:是
java.lang.invoke.MethodHandle
的一個(gè)實(shí)例,它是對(duì)Java中某個(gè)方法(包括實(shí)例方法、靜態(tài)方法、構(gòu)造函數(shù)等)的直接可執(zhí)行引用。
特點(diǎn)
- 輕量級(jí)和高效:與傳統(tǒng)的Java反射相比,MethodHandle更加輕量級(jí)和高效,因?yàn)樗@過(guò)了許多反射的額外開(kāi)銷,如訪問(wèn)控制檢查等。
- 直接可執(zhí)行:MethodHandle是對(duì)方法的直接引用,可以直接通過(guò)MethodHandle對(duì)象調(diào)用目標(biāo)方法,無(wú)需像反射那樣先獲取Method對(duì)象。
- 類型化:MethodHandle具有類型檢查的特性,在編譯時(shí)會(huì)檢查MethodHandle的類型與目標(biāo)方法的類型是否匹配。
使用流程
引入JDK:確保開(kāi)發(fā)環(huán)境已經(jīng)引入了支持MethodHandle的JDK版本(Java SE 7及以上)。
創(chuàng)建MethodHandle對(duì)象:
- 使用
MethodHandles.Lookup
類的lookup()
方法獲取一個(gè)MethodHandles.Lookup
對(duì)象。 - 使用
MethodHandles.Lookup
對(duì)象的findStatic()
,findVirtual()
,findSpecial()
,findConstructor()
等方法來(lái)查找并獲取目標(biāo)方法的MethodHandle對(duì)象。
綁定MethodHandle到目標(biāo)方法(如果需要):
- 如果MethodHandle指向的是實(shí)例方法,可以使用
MethodHandle
對(duì)象的bindTo()
方法將其綁定到目標(biāo)實(shí)例上。
調(diào)用目標(biāo)方法:
- 使用MethodHandle對(duì)象的
invoke()
、invokeExact()
、invokeWithArguments()
等方法來(lái)調(diào)用目標(biāo)方法。
與反射的區(qū)別
- 性能:MethodHandle通常比反射更快,因?yàn)樗@過(guò)了許多反射的額外開(kāi)銷。
- 類型安全:MethodHandle在編譯時(shí)會(huì)進(jìn)行類型檢查,而反射在運(yùn)行時(shí)進(jìn)行類型檢查,可能導(dǎo)致
ClassCastException
等異常。 - 用法:反射需要先獲取
Method
對(duì)象,而MethodHandle直接對(duì)方法進(jìn)行引用。
示例:
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class MethodHandleExample { public static void main(String[] args) throws Throwable { // 查找String類的startsWith方法 MethodHandle handle = MethodHandles.lookup() .findVirtual(String.class, "startsWith", MethodType.methodType(boolean.class, String.class)); // 調(diào)用startsWith方法 boolean result = (Boolean) handle.invokeExact("Hello, World!", "Hello"); System.out.println(result); // 輸出: true } }
當(dāng)使用Java的java.lang.invoke.MethodHandle
來(lái)調(diào)用實(shí)例方法時(shí),你需要首先獲取到該實(shí)例方法的MethodHandle
,然后你可以使用invoke()
、invokeExact()
或invokeWithArguments()
方法來(lái)調(diào)用它。
以下是使用invokeExact()
方法調(diào)用實(shí)例方法的一個(gè)例子:
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class MyClass { public int myMethod(String param, int number) { System.out.println("Inside myMethod: " + param + ", " + number); return number * 2; } public static void main(String[] args) throws Throwable { // 創(chuàng)建MyClass的實(shí)例 MyClass obj = new MyClass(); // 查找myMethod的MethodHandle // 注意:由于我們是在MyClass內(nèi)部查找,所以可以使用MethodHandles.lookup() // 在實(shí)際應(yīng)用中,如果MyClass是其他包中的類,你可能需要不同的Lookup實(shí)例 MethodHandle mh = MethodHandles.lookup() .findVirtual(MyClass.class, "myMethod", MethodType.methodType(int.class, String.class, int.class)); // 使用invokeExact調(diào)用myMethod // 注意:invokeExact要求參數(shù)類型嚴(yán)格匹配,包括返回類型 int result = (int) mh.invokeExact(obj, "Hello", 42); // 輸出結(jié)果 System.out.println("Result: " + result); } }
在上面的例子中,我們首先創(chuàng)建了一個(gè)MyClass
的實(shí)例obj
。然后,我們使用MethodHandles.lookup().findVirtual()
方法查找myMethod
的MethodHandle
。
注意,findVirtual
方法需要三個(gè)參數(shù):目標(biāo)類的Class
對(duì)象、方法名以及一個(gè)描述方法簽名的MethodType
對(duì)象。
在獲取到MethodHandle
之后,我們使用invokeExact
方法來(lái)調(diào)用myMethod
。因?yàn)?code>myMethod的返回類型是int
,并且它接受一個(gè)String
和一個(gè)int
作為參數(shù),所以我們傳遞了正確的參數(shù)類型給invokeExact
,并且使用了一個(gè)強(qiáng)制類型轉(zhuǎn)換來(lái)將結(jié)果從Object
轉(zhuǎn)換為int
。
invoke()、invokeExact()、invokeWithArguments()區(qū)別
在Java的java.lang.invoke
包中,MethodHandle
類提供了幾種不同的方法來(lái)動(dòng)態(tài)調(diào)用目標(biāo)方法。以下是invoke()
、invokeExact()
和invokeWithArguments()
這三種方法之間的主要區(qū)別:
1. invoke()
特點(diǎn):
invoke()
方法是MethodHandle的一個(gè)通用方法,它允許在調(diào)用時(shí)執(zhí)行類型轉(zhuǎn)換。- 如果提供的參數(shù)類型與目標(biāo)方法不匹配,
invoke()
會(huì)嘗試使用MethodHandle
的asType()
方法進(jìn)行參數(shù)適配。
參數(shù):
invoke()
方法接受一個(gè)可變參數(shù)列表(Object... args
),其中第一個(gè)參數(shù)(如果目標(biāo)方法是實(shí)例方法)是實(shí)例對(duì)象,后續(xù)參數(shù)是傳遞給目標(biāo)方法的參數(shù)。
示例:
MethodHandle mh = ... // 獲取MethodHandle的實(shí)例 Object result = mh.invoke(obj, arg1, arg2, ...);
2. invokeExact()
特點(diǎn):
invokeExact()
方法提供了嚴(yán)格的類型檢查。- 如果提供的參數(shù)類型與目標(biāo)方法的參數(shù)類型不匹配,
invokeExact()
將拋出WrongMethodTypeException
。
參數(shù):
invokeExact()
同樣接受一個(gè)可變參數(shù)列表(Object... args
),但要求這些參數(shù)的類型必須與目標(biāo)方法的參數(shù)類型完全匹配。
示例:
MethodHandle mh = ... // 獲取MethodHandle的實(shí)例 Object result = mh.invokeExact(obj, arg1, arg2, ...); // 確保類型匹配
3. invokeWithArguments()
特點(diǎn):
invokeWithArguments()
方法允許使用List<Object>
作為參數(shù)列表進(jìn)行調(diào)用。- 這為調(diào)用者提供了一種更靈活的方式來(lái)構(gòu)建參數(shù)列表,尤其是當(dāng)參數(shù)數(shù)量不確定或需要?jiǎng)討B(tài)構(gòu)建時(shí)。
參數(shù):
invokeWithArguments()
接受一個(gè)List<Object>
參數(shù),其中第一個(gè)元素(如果目標(biāo)方法是實(shí)例方法)是實(shí)例對(duì)象,后續(xù)元素是傳遞給目標(biāo)方法的參數(shù)。
示例:
MethodHandle mh = ... // 獲取MethodHandle的實(shí)例 List<Object> arguments = Arrays.asList(obj, arg1, arg2, ...); Object result = mh.invokeWithArguments(arguments);
4. 歸納
invoke()
:提供類型適配的靈活調(diào)用,允許在運(yùn)行時(shí)轉(zhuǎn)換參數(shù)類型。invokeExact()
:提供嚴(yán)格的類型檢查,要求參數(shù)類型與目標(biāo)方法完全匹配。invokeWithArguments()
:允許使用列表作為參數(shù)進(jìn)行調(diào)用,提供了更大的靈活性。
在選擇使用哪種方法時(shí),應(yīng)該根據(jù)具體需求來(lái)決定。如果希望進(jìn)行嚴(yán)格的類型檢查,可以使用invokeExact()
;如果需要更靈活的參數(shù)傳遞方式,可以考慮使用invoke()
或invokeWithArguments()
。同時(shí),需要注意的是,invokeExact()
的性能通常優(yōu)于invoke()
,因?yàn)樗苊饬嗽谶\(yùn)行時(shí)進(jìn)行類型適配的開(kāi)銷。
總結(jié)
Java的MethodHandle提供了一種高效、輕量級(jí)且類型安全的方法來(lái)動(dòng)態(tài)調(diào)用Java方法。通過(guò)MethodHandle,開(kāi)發(fā)者可以更加靈活和高效地操作Java代碼中的方法。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring security與corsFilter沖突的解決方案
這篇文章主要介紹了spring security與corsFilter沖突的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java代碼性能測(cè)試實(shí)戰(zhàn)之ContiPerf安裝使用
這篇文章主要為大家介紹了Java代碼性能測(cè)試實(shí)戰(zhàn)之ContiPerf安裝使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06自定義注解和springAOP捕獲Service層異常,并處理自定義異常操作
這篇文章主要介紹了自定義注解和springAOP捕獲Service層異常,并處理自定義異常操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06java基于正則提取字符串中的數(shù)字功能【如提取短信中的驗(yàn)證碼】
這篇文章主要介紹了java基于正則提取字符串中的數(shù)字功能,可用于提取短信中的驗(yàn)證碼,涉及java基于正則的字符串匹配相關(guān)操作技巧,需要的朋友可以參考下2017-01-01java對(duì)xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇java對(duì)xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10Java?Spring?AOP源碼解析之事務(wù)實(shí)現(xiàn)原理
這篇文章主要為大家介紹了Java?Spring?AOP事務(wù)實(shí)現(xiàn)原理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-01-01Spring注解驅(qū)動(dòng)開(kāi)發(fā)實(shí)現(xiàn)屬性賦值
這篇文章主要介紹了Spring注解驅(qū)動(dòng)開(kāi)發(fā)實(shí)現(xiàn)屬性賦值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Java中的HashSet、LinkedHashSet集合解析
這篇文章主要介紹了Java中的HashSet、LinkedHashSet集合解析,與HashSet不同的是,LinkedHashSet在內(nèi)部使用了一個(gè)雙向鏈表來(lái)維護(hù)元素的順序,因此它可以保持元素的插入順序,這使得LinkedHashSet在需要保持元素順序的場(chǎng)景下非常有用,需要的朋友可以參考下2023-11-11