偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

優(yōu)于反射(Reflection):在Java中使用方法句柄和變量句柄

譯文 精選
開發(fā) 前端
反射多年來一直是高級Java工具包的關(guān)鍵?,F(xiàn)在,它正在被更先進(jìn)、更安全的選項所取代。下文介紹了如何使用MethodHandle和VarHandle來獲得對方法和字段的編程訪問。

譯者 | 晶顏

審校 | 重樓

區(qū)分資深Java開發(fā)人員的因素之一是熟悉反射(reflection)及其先進(jìn)替代品。反射為Java開發(fā)提供了超能力,但它很麻煩,容易出錯,并且存在性能瓶頸?,F(xiàn)代Java正在努力用標(biāo)準(zhǔn)化的選項取代反射,包括方法句柄(MethodHandle變量句柄(VarHandle。與反射一樣,這些類也允許你訪問對象上的方法和字段,但使用的是更清晰的API。

句柄的力量

顧名思義,MethodHandle和VarHandle都為你提供了句柄,它們是引用對象元屬性的變量。這些句柄使你能夠直接處理方法和字段。它們是特殊的變量,引用運行時環(huán)境的某些部分,否則將對代碼隱藏。

這些功能的起點是MethodHandle上的各種查找方法,這些方法提供了一種以編程方式查找類元數(shù)據(jù)的現(xiàn)代方法。這類似于舊的反射API的方法,如getDeclaredMethod,但具有更多的結(jié)構(gòu)和安全性。

一旦有了類元數(shù)據(jù)的句柄,就可以使用MethodHandle和VarHandle以編程方式對類實例上存在的方法和字段進(jìn)行調(diào)用。在底層,JVM管理這些方法,通常比使用反射獲得更好的性能。

方法和變量句柄 VS. Java反射

要真正理解MethodHandles和Varhandles——它們是做什么的以及它們?yōu)槭裁从杏谩私庖恍╆P(guān)于Java反射的知識是有幫助的。這將幫助你理解為什么反射會演變成這些較新的API。

最根本的問題是這些技術(shù)——反射、方法句柄、變量句柄——需要滿足什么需求?當(dāng)我們可以簡單地實例化一個對象,調(diào)用它的公共方法并訪問它的公共成員時,我們?yōu)槭裁匆镁幊痰姆绞絹碜鲞@些事情呢?

在很多情況下,不能通過公共方法訪問需要的程序,所以必須繞過正常的路線。這主要發(fā)生在你編寫類似框架代碼時,該代碼對一系列類進(jìn)行操作并對它們進(jìn)行非標(biāo)準(zhǔn)操作。

以一個持久性框架為例,你需要將類映射到表和表之間,因此你需要內(nèi)省(Introspect)類以了解它們具有哪些字段和方法。這種情況也會出現(xiàn)在應(yīng)用程序代碼中,特別是當(dāng)你需要訪問遺留庫中無法訪問的部分時。

決定使用哪種技術(shù)要了解需要什么。如果你可以使用普通的Java調(diào)用來解決這個問題,那么就是可行的方法。如果需要更復(fù)雜的東西,先看看標(biāo)準(zhǔn)的API(比如MethodHandles和VarHandles。只有當(dāng)這些都無法實現(xiàn)時,才應(yīng)該轉(zhuǎn)而依靠反射。

下述示例可以幫助你理解為什么JAVA開發(fā)工具包(JDK)更喜歡句柄而傳統(tǒng)的Java反射。

使用反射來訪問方法

我們將從一個反射示例開始,因為它很常見,并且會給我們一個已知的參考。請記住,這是最后的解決方案。

假設(shè)有這個類:

public class MyClass {
 private String name;
 public MyClass(String name) {
 this.name = name;
 }
 public String getName() { 
 return name;
 }
}

這是一個非常簡單的事情只是一個用于保存字符串名的類。要創(chuàng)建這個類,我們可以使用普通實例化

MyClass objectInstance = new MyClass("John Doe");

下面是使用反射訪問該方法的示例:

Class<?> clazz = objectInstance.getClass();
Method method = clazz3.getDeclaredMethod("getName");
String value = (String) method.invoke(objectInstance);
System.out.println(value); // prints "John Doe"

使用MethodHandles來訪問方法

方法句柄為我們提供了與反射相同的功能,但語法更安全

Class<?> clazz = objectInstance.getClass(); 
MethodHandle handle = MethodHandles.lookup().findVirtual(clazz, "getName", methodType(String.class));
String value = (String) handle.invoke(objectInstance);
System.out.println(value); // Prints “John Doe”

我們以同樣的方式開始,從實例中獲取類。然后,我們在MethodHandles上使用lookup(). findvirtual()方法。這是MethodHandles設(shè)計的主要目的之一提供一種更簡潔、JDK認(rèn)可的方法來查找方法。這種方法還針對JVM優(yōu)化進(jìn)行了增強(qiáng)。

接下來,我們將使用handle.invoke調(diào)用帶有句柄的方法并傳入對象實例。

直接訪問字段

假設(shè)我們之前的類MyClass上面有name字段但沒有訪問器。我們現(xiàn)在需要更強(qiáng)的程序來訪問它,因為我們要直接訪問私有成員(Private Member)。下面是我們使用標(biāo)準(zhǔn)反射的方法

Class<?> clazz = objectInstance.getClass(); 
Field field = clazz.getDeclaredField("name"); 
field.setAccessible(true); 
String value = (String) field.get(objectInstance);
System.out.println(value); // prints “John Doe”

注意,我們再次直接處理對象的元數(shù)據(jù),比如它的類和它的字段。我們可以使用setAccessible操作字段的可訪問性這被認(rèn)為是有風(fēng)險的,因為它可能會改變目標(biāo)代碼所寫的限制。這是使私有字段對我們可見的關(guān)鍵部分。

現(xiàn)在讓我們使用變量句柄做同樣的事情

Class<?>l clazz = objectInstance.getClass();
VarHandle handle = MethodHandles.privateLookupIn(clazz, 
 MethodHandles.lookup()).findVarHandle(clazz, "name", String.class);
String value = (String) handle.get(objectInstance);
System.out.println(value4); // prints "John Doe"

這里,我們使用privateLookupIn,因為該字段被標(biāo)記為私有Private。還有一個通用lookup(),它將尊重訪問修飾符,因此它更安全,但不會找到私有字段。

雖然上面的代碼可以運行,但出于性能原因,建議靜態(tài)地實例化句柄本身,如下所示

private static VarHandle HANDLE;
 static {
 try {
 HANDLE = MethodHandles.privateLookupIn(MyClass.class, MethodHandles.lookup()).findVarHandle(MyClass.class, "name", String.class);
 } catch (Throwable t){
 throw new RuntimeException(t);
 }
 }

// …

System.out.println("static: " + HANDLE.get(objectInstance));

這里,我們靜態(tài)地實例化了HANDLE變量,然后在稍后的正常代碼流中使用它。這也突出了句柄本身是為類型MyClass定義的,然后為實例(ObjectInstance重用。

注意,直接實例化句柄需要知道類的名稱。如果你不知道類的名稱,則不能使用這種方法。

方法和變量句柄的限制

盡管它們?yōu)闃?biāo)準(zhǔn)化的JDK帶來了強(qiáng)大的功能,但方法句柄和變量句柄并不打算涵蓋Java反射API中的所有功能。它們只是涵蓋了一個重點范圍查找類元數(shù)據(jù)并使用它來訪問常規(guī)Java限制之外的方法和字段。其余sun.misc. Unsafe中的反射力量正逐漸被其他包所取代。

如前所述,MethodHandles和VarHandle不支持實例化類,這在某些情況下會產(chǎn)生限制。

是時候思考反射替代方案了

花點時間說服自己遠(yuǎn)離反射是必要的,也是值得的。如果你研究了基準(zhǔn)測試,就會發(fā)現(xiàn)方法句柄和變量句柄的性能普遍優(yōu)于反射。另一方面,它們更安全、更地道,并且JVM代碼庫正在采用這些方法它們的普及也只是時間問題而已。

在基準(zhǔn)測試中,靜態(tài)聲明句柄可以顯著提高性能。這是因為JVM可以在編譯時內(nèi)聯(lián)這些信息。但是,如前所述,這樣做并總是可——例如,如果你在編譯時不知道類的名稱。

除了性能之外,基于正確性等因素考慮,反射也正逐漸被棄用。最終,無論如何都需要遷移工作?,F(xiàn)在是時候開始移動代碼庫中那些具有現(xiàn)代替代品如MethodHandles和VarHandle的部分了!

原文標(biāo)題:Better than reflection: Using method handles and variable handles in Java,作者:Matthew Tyson

責(zé)任編輯:華軒 來源: 51CTO
相關(guān)推薦

2023-01-28 17:41:07

Java代碼

2024-04-10 09:08:05

WPFWinForms.NET

2011-05-17 16:20:46

C++

2011-03-30 10:41:11

C++數(shù)據(jù)庫

2009-06-17 13:57:54

java實例Reflection

2011-09-02 19:24:20

SqliteIOS應(yīng)用數(shù)據(jù)庫

2010-08-11 09:40:44

LINQ

2015-04-17 16:44:22

swiftOC

2014-07-28 10:00:47

linux系統(tǒng)調(diào)試句柄

2010-07-14 15:23:19

Perl文件句柄

2011-04-08 10:43:44

2009-09-15 17:46:08

C#綁定句柄無效

2021-03-18 10:14:06

Python工具代碼

2009-06-24 10:49:08

Unix

2021-01-27 10:56:05

Linux運維Linux系統(tǒng)

2010-07-15 14:01:10

Perl目錄句柄

2023-05-04 07:33:39

Rust變量常量

2009-12-01 17:00:49

PHP變量

2024-09-18 00:00:02

反射C#元數(shù)據(jù)

2013-07-15 15:12:40

iOS多線程NSOperationNSOperation
點贊
收藏

51CTO技術(shù)棧公眾號