日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小度拆卸_拆卸invokedynamic

發布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小度拆卸_拆卸invokedynamic 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

小度拆卸

許多Java開發人員認為JDK的第七版有些令人失望。 從表面上看,僅少數語言和庫擴展使它成為了發行版,即Project Coin和NIO2 。 但在幕后,該平臺的第七個版本對JVM類型系統進行了最大的擴展,這是其最初發行后引入的。 添加invokedynamic指令不僅為在Java 8中實現lambda表達式奠定了基礎,而且還是將動態語言轉換為Java字節碼格式的規則改變者。

雖然invokedynamic指令是用于在Java虛擬機上執行語言的實現細節,但了解該指令的功能可以真正洞悉執行Java程序的內部工作原理。 本文提供了有關invokedynamic指令解決什么問題以及如何解決它的初學者的見解。

方法句柄

方法句柄通常被描述為Java反射API的改進版本,但這并不是它們所代表的意思。 盡管方法句柄確實表示方法,構造函數或字段,但它們并不旨在描述這些類成員的屬性。 例如,不可能直接從方法句柄中提取元數據,例如所表示方法的修飾符或注釋值。 雖然方法句柄允許引用方法的調用,但它們的主要目的是與invokedynamic調用站點一起使用。 為了更好地理解方法句柄,將它們視為反射API的不完美替代是一個合理的起點。

方法句柄無法實例化。 而是使用指定的查找對象創建方法句柄。 這些對象本身是使用MethodHandles類提供的工廠方法創建的。 每當調用工廠時,它都會首先創建一個安全上下文,以確保所生成的查找對象只能定位對調用工廠方法的類也可見的方法。 然后可以按以下方式創建查找對象:

class Example {void doSomething() {MethodHandles.Lookup lookup = MethodHandles.lookup();} }

如前所述,以上查找對象只能用于定位對Example類也可見的方法。 例如,不可能查找另一個類的私有方法。 這是使用反射API的第一個主要區別,反射API可以像定位其他任何方法一樣定位外部類的私有方法,并且在將此類方法標記為可訪問之后甚至可以調用這些方法。 因此,方法句柄對它們的創建上下文很敏感,這是與反射API的第一個主要區別。

除此之外,方法句柄通過描述特定類型的方法而不是僅代表任何方法,比反射API更具體。 在Java程序中,方法的類型是該方法的返回類型及其參數類型的組合。 例如,以下Counter類的only方法返回一個int,它表示唯一的String型參數的字符數:

class Counter {static int count(String name) {return name.length();} }

可以使用另一個工廠來創建此方法類型的表示形式。 該工廠位于MethodType類中,該類還表示創建的方法類型的實例。 使用該工廠,可以通過移交方法的返回類型及其捆綁為數組的參數類型來創建Counter::count的方法類型:

MethodType methodType = MethodType.methodType(int.class, new Class<?>[] {String.class});

描述上述方法的類型時,將方法聲明為靜態是很重要的。 編譯Java方法時,非靜態Java方法的表示方式類似于靜態方法,但帶有一個表示此偽變量的附加隱式參數。 因此,在為非靜態方法創建MethodType時,需要傳遞代表該方法的聲明類型的附加參數。 因此,對于上述Counter::count方法的非靜態版本,方法類型將變為以下類型:

MethodType.methodType(int.class, Example.class, new Class<?>[] {String.class});

通過使用之前創建的查找對象以及上面的方法類型,現在可以找到代表Counter::count方法的方法句柄,如以下代碼所示:

MethodType methodType = MethodType.methodType(int.class, new Class<?>[] {String.class}); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle methodHandle = lookup.findStatic(Counter.class, "count", methodType); int count = methodHandle.invokeExact("foo"); assertThat(count, is(3));

乍一看,使用方法句柄似乎是使用反射API的過于復雜的版本。 但是,請記住,使用句柄直接調用方法并不是其使用的主要目的。

上面的示例代碼和通過反射API調用方法的主要區別僅在研究Java編譯器將兩次調用轉換為Java字節碼的方式的區別時才顯示出來。 當Java程序調用方法時,該方法由其名稱,其(非通用)參數類型以及其返回類型唯一標識。 因此,可以重載Java中的方法。 即使Java編程語言不允許這樣做,但JVM在理論上確實允許通過其返回類型來重載方法。

遵循此原理,將反射方法調用作為Method :: invoke方法的公共方法調用執行。 此方法由其兩個參數(類型為Object和Object [])標識。 除此之外,該方法還通過其對象返回類型來標識。 由于具有此簽名,因此必須始終將此方法的所有參數裝箱并包含在數組中。 同樣,如果返回值是原始值,則需要將其裝箱;如果該方法無效,則返回null。

方法句柄是該規則的例外。 不是通過引用MethodHandle::invokeExact簽名的方法來調用方法句柄,該簽名將Object[]作為其單個參數并返回Object ,而是使用所謂的多態簽名來調用方法句柄。 Java編譯器根據調用現場的實際參數類型和期望的返回類型來創建多態簽名。 例如,當使用

int count = methodHandle.invokeExact("foo");

Java編譯器將轉換此調用,就像將invokeExact方法定義為接受String類型的單個單個參數并返回int類型一樣。 顯然,這種方法不存在,并且對于(幾乎)任何其他方法,這將在運行時導致鏈接錯誤。 對于方法句柄,Java虛擬機確實將此簽名識別為多態的,并且將方法句柄的調用視為該句柄所引用的Counter::count方法直接插入到調用站點中。 因此,可以調用該方法而無需將原始值裝箱或返回類型的開銷,也無需將參數值放在數組內。

同時,在使用invokeExact調用時,向Java虛擬機保證方法句柄在運行時始終引用與多態簽名兼容的方法。 對于該示例,JVM期望所引用的方法實際上接受String作為其唯一參數,并且它返回原始int 。 如果未滿足此約束,則執行將導致運行時錯誤。 但是,任何其他接受單個String并返回原始int的方法都可以成功地填充到方法句柄的調用站點中,以替換Counter::count 。

相反,即使代碼成功編譯,在以下三個調用中使用Counter::count方法句柄也會導致運行時錯誤:

int count1 = methodHandle.invokeExact((Object) "foo"); int count2 = (Integer) methodHandle.invokeExact("foo"); methodHandle.invokeExact("foo");

第一條語句導致錯誤,因為傳遞給句柄的參數過于籠統。 盡管JVM期望將String作為方法的參數,但Java編譯器建議該參數為Object類型。 重要的是要理解,Java編譯器將強制轉換作為創建不同的多態簽名的提示,該簽名將Object類型作為單個參數類型,而JVM在運行時期望使用String 。 請注意,此限制也適用于處理過于具體的參數,例如,將參數強制轉換為Integer ,該方法的句柄需要使用Number類型作為其參數。 在第二條語句中,Java編譯器向運行時建議,句柄的方法將返回Integer包裝器類型,而不是原始int 。 而且,在第三條語句中根本不建議返回類型,Java編譯器將調用隱式轉換為void方法調用。 因此, invokeExact確實意味著精確。

這種限制有時可能太苛刻。 出于這個原因,方法句柄不需要進行確切的調用,還允許在應用了諸如類型轉換和拳擊等轉換的情況下更為寬容的調用。 可以通過使用MethodHandle::invoke方法來應用MethodHandle::invoke 。 使用此方法,Java編譯器仍會創建一個多態簽名。 但這一次,Java虛擬機確實在運行時測試了實際參數和返回類型的兼容性,并在適當時通過應用裝箱或轉換來轉換它們。 顯然,這些轉換有時會增加運行時的開銷。

字段,方法和構造函數:作為統一接口處理

除了反射API的Method實例之外,方法句柄可以同樣引用字段或構造函數。 因此,可以將MethodHandle類型的名稱視為太窄。 實際上,在運行時通過方法句柄引用哪個類成員并不重要,只要它的MethodType (具有誤導性名稱的另一種類型)與在關聯的調用站點傳遞的參數匹配即可。

使用MethodHandles.Lookup對象的適當工廠,可以查找一個字段以表示一個getter或setter。 在此上下文中使用getter或setter并不表示調用遵循Java Bean規范的實際方法。 而是,基于字段的方法句柄直接從字段讀取或寫入字段,但通過調用方法句柄以方法調用的形式出現。 通過經由方法句柄表示此類字段訪問,可以互換使用字段訪問或方法調用。

以此類交換為例,采用以下類:

class Bean {String value;void print(String x) {System.out.println(x);} }

給定此Bean類,可以使用以下方法句柄將字符串寫到value字段或使用與參數相同的字符串調用print方法:

MethodHandle fieldHandle = lookup.findSetter(Bean.class, "value", String.class); MethodType methodType = MethodType.methodType(void.class, new Class<?>[] {String.class}); MethodHandle methodHandle = lookup.findVirtual(Bean.class, "print", methodType);

只要在返回void同時將方法句柄調用站點與String一起傳遞給Bean的實例,則兩個方法句柄可以互換使用,如下所示:

anyHandle.invokeExact((Bean) mybean, (String) myString);

與字段和方法類似,可以定位和調用構造函數。 此外,只要創建查找工廠的類可以訪問此超級方法,則它不僅可以直接調用方法,甚至可以調用超級方法。 相反,在依賴反射API時根本不可能調用超級方法。 如果需要,甚至可以從句柄返回恒定值。

性能指標

方法句柄通常被描述為比Java反射API更高性能。 至少對于最新版本的HotSpot虛擬機而言,這不是事實。 證明這一點的最簡單方法是編寫適當的基準 。 再說一次,為Java程序編寫基準并在執行時進行優化并不是一件容易的事。 編寫基準的事實上的標準已成為使用JMH的工具,JMH是OpenJDK旗下的工具。 完整的基準可以在我的GitHub個人資料中找到要點。 本文僅涵蓋該基準測試的最重要方面。

從基準來看,很明顯反射已經非常有效地實現了。 現代JVM知道一個稱為膨脹的概念,其中經常調用的反射方法調用被運行時生成的Java字節代碼替換。 剩下的是將拳擊用于傳遞參數和接收返回值的開銷。 有時可以通過JVM的即時編譯器消除這些拳擊,但這并不總是可能的。 因此,如果方法調用涉及大量原始值,則使用方法句柄可能比使用反射API更有效。 但是,這確實要求在編譯時已經知道確切的方法簽名,以便可以創建適當的多態簽名。 對于大多數反射API用例,由于在編譯時不知道被調用方法的類型,因此無法提供此保證。 在這種情況下,使用方法句柄不會帶來任何性能上的好處,因此不應替換它。

創建一個invokedynamic呼叫站點

通常,僅當Java編譯器需要將lambda表達式轉換為字節碼時,才會創建invokedynamic調用站點。 值得一提的是,lambda表達式可以在沒有完全調用動態調用站點的情況下實現,例如通過將它們轉換為匿名內部類。 與建議的方法的主要區別是,使用invokedynamic會延遲創建與運行時類似的類。 我們將在下一部分中研究類的創建。 但是,現在請記住,invokedynamic與類創建沒有任何關系,它僅允許將如何調度方法的決定延遲到運行時。

為了更好地理解invokedynamic調用站點,它有助于顯式創建此類調用站點,以便單獨查看機制。 為此,下面的示例利用了我的代碼生成框架Byte Buddy ,該框架提供了對invokedynamic調用站點的顯式字節代碼生成,而無需任何字節代碼格式的知識。

任何invokedynamic調用站點最終都會產生一個MethodHandle,該MethodHandle引用要調用的方法。 但是,不是手動調用此方法句柄,而是由Java運行時決定。 因為方法句柄已成為Java虛擬機的已知概念,所以這些調用的優化類似于常見方法調用。 任何這樣的方法句柄都是從所謂的引導程序方法接收的,而引導程序方法僅是滿足特定簽名的普通Java方法。 有關引導方法的簡單示例,請查看以下代碼:

class Bootstrapper {public static CallSite bootstrap(Object... args) throws Throwable {MethodType methodType = MethodType.methodType(int.class, new Class<?>[] {String.class})MethodHandles.Lookup lookup = MethodHandles.lookup();MethodHandle methodHandle = lookup.findStatic(Counter.class, "count", methodType);return new ConstantCallSite(methodHandle);} }

目前,我們不太關心該方法的參數。 相反,請注意,該方法是靜態的,實際上是必需的。 在Java字節代碼中,invokedynamic調用站點引用引導程序方法的完整簽名,但不引用可能具有狀態和生命周期的特定對象。 調用invokedynamic調用站點后,控制流將移交給引用的引導方法,該方法現在負責標識方法句柄。 從bootstrap方法返回此方法句柄后,它將由Java運行時調用。

從上面的示例可以明顯看出, MethodHandle不是直接從引導方法返回的。 而是將句柄包裝在CallSite對象的內部。 每當調用引導方法時,invokedynamic調用站點便會永久綁定到從該方法返回的CallSite對象。 因此,對于任何呼叫站點僅一次調用引導程序方法。 由于有了這個中間的CallSite對象,因此可以在以后交換引用的MethodHandle 。 為此,Java類庫已經提供了CallSite不同實現。 在上面的示例代碼中,我們已經看到了ConstantCallSite 。 顧名思義, ConstantCallSite始終引用相同的方法句柄,而不會在以后進行交換。 但是,也可以選擇使用MutableCallSite ,它允許在以后的某個時間點更改引用的MethodHandle ,或者甚至有可能實現自定義的CallSite類。

通過上述引導程序方法和Byte Buddy,我們現在可以實現自定義invokedynamic指令。 為此,Byte Buddy提供了InvokeDynamic工具,該工具接受bootstrap方法作為其唯一的強制參數。 然后將這樣的儀器輸入到Byte Buddy。 假設下面的類:

abstract class Example {abstract int method(); }

我們可以使用Byte Buddy來對Example進行子類化,以覆蓋method 。 然后,我們將實現此方法以包含單個invokedynamic調用站點。 無需任何進一步配置,Byte Buddy就會創建一個類似于覆蓋方法的方法類型的多態簽名。 請記住,對于非靜態方法,此引用將作為第一個隱式參數處理。 假定我們要綁定將String作為單個參數的Counter::count方法,則無法將此句柄綁定到與方法類型不匹配的Example::method 。 因此,我們需要創建一個不帶隱式參數但使用String代替的其他調用站點。 這可以通過使用Byte Buddy的域特定語言來實現:

Instrumentation invokeDynamic = InvokeDynamic.bootstrap(Bootstrapper.class.getDeclaredMethod(“bootstrap”, Object[].class)).withoutImplicitArguments().withValue("foo");

有了此工具,我們最終可以擴展Example類和重寫方法,以實現invokedynamic調用站點,如以下代碼片段所示:

Example example = new ByteBuddy().subclass(Example.class).method(named(“method”)).intercept(invokeDynamic).make().load(Example.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION).getLoaded().newInstance(); int result = example.method(); assertThat(result, is(3));

從上面的斷言可以明顯看出, "foo"字符串的字符已正確計數。 通過在代碼中設置適當的斷點,還可以驗證是否調用了bootstrap方法,并且控制流進一步到達了Counter::count方法。

到目前為止,使用invokedynamic調用站點并沒有帶來太多好處。 上面的bootstrap方法將始終綁定Counter::count ,因此只有在invokedynamic調用站點確實想要將String轉換為int時才可以產生有效結果。 顯然,由于引導方法從invokedynamic調用站點接收到的參數,因此引導方法可以更加靈活。 任何引導方法都至少接收三個參數:

作為第一個參數,bootstrap方法接收一個MethodHandles.Lookup對象。 該對象的安全上下文是包含觸發自舉的invokedynamic調用站點的類的安全上下文。 如前所述,這意味著可以使用此查找實例將定義類的私有方法綁定到invokedynamic調用站點。

第二個參數是一個表示方法名稱的String 。 該字符串用作提示,指示從調用站點應將哪種方法綁定到它。 嚴格來說,不需要此參數,因為將方法與其他名稱綁定是完全合法的。 如果沒有另外指定,Byte Buddy僅將覆蓋方法的名稱用作此參數。

最后,將預期返回的方法句柄的MethodType用作第三個參數。 對于上面的示例,我們明確指定希望將String作為單個參數。 同時,Byte Buddy通過查看重寫的方法得出我們需要一個int作為返回值,因為我們再次沒有指定任何顯式的返回類型。

引導程序方法的實現者應取決于引導程序方法的確切簽名,只要它至少可以接受這三個參數即可。 如果引導程序方法的最后一個參數表示Object數組,則該最后一個參數將被視為varargs,因此可以接受任何多余的參數。 這也是上述示例引導程序方法有效的原因。

此外,引導程序方法可以從invokedynamic調用站點接收多個參數,只要這些參數可以存儲在類的常量池中即可。 對于任何Java類,常量池都存儲在類內部使用的值,主要是數字或字符串值。 從今天起,此類常量可以是至少32位大小的原始值, String , Class , MethodHandl和MethodType 。 如果查找合適的方法句柄需要此類參數形式的附加信息,則可以使引導方法更靈活地使用。

Lambda表達式

每當Java編譯器將lambda表達式轉換為字節碼時,它都會將lambda的主體復制到定義該表達式的類內部的私有方法中。 這些方法被命名為lambda$X$Y其中X是包含lambda表達式的方法的名稱,而Y是從零開始的序列號。 這種方法的參數是lambda表達式實現的功能接口的參數。 假定lambda表達式不使用非靜態字段或封閉類的方法,則該方法也定義為靜態的。

為了進行補償,lambda表達式本身被invokedynamic調用站點替代。 在調用時,此調用站點請求為功能接口的實例綁定工廠。 作為此工廠的參數,調用站點提供了在表達式內部使用的lambda表達式的封閉方法的任何值,并在需要時提供對封閉實例的引用。 作為返回類型,要求工廠提供功能接口的實例。

為了引導呼叫站點,當前任何invokedynamic指令都委托給Java類庫中包含的LambdaMetafactory類。 然后,該工廠負責創建一個實現功能接口的類,該類調用包含lambda主體的適當方法,該主體如前所述存儲在原始類中。 但是,將來這種引導過程可能會更改,這是使用invokedynamic來實現lambda表達式的主要優點之一。 如果有一天,可以使用一種更適合的語言功能來實現lambda表達式,則可以簡單地替換掉當前的實現。

為了能夠創建實現功能接口的類,任何表示lambda表達式的調用站點都會為bootstrap方法提供其他參數。 對于強制性參數,它已經提供了功能接口方法的名稱。 而且,它提供了引導應該產生的工廠方法的MethodType 。 此外,為引導方法提供了另一個MethodType ,它描述了功能接口方法的簽名。 為此,它接收到一個MethodHandle該方法引用包含lambda的方法主體的方法。 最后,調用站點提供了功能接口方法的通用簽名的MethodType ,即在應用類型擦除之前在調用站點上方法的簽名。

調用時,bootstrap方法將查看這些參數,并創建實現功能接口的類的適當實現。 此類是使用ASM庫創建的, ASM庫是一種低級字節代碼解析器和編寫器,它已成為直接Java字節代碼操作的事實上的標準。 bootstrap方法除了實現功能接口的方法外,還添加了適當的構造函數和靜態工廠方法來創建類的實例。 此工廠方法后來綁定到invokedyanmic調用站點。 作為自變量,工廠將接收lambda方法的封閉實例的實例,以防其被訪問以及從封閉方法中讀取的任何值。

例如,請考慮以下lambda表達式:

class Foo {int i;void bar(int j) {Consumer consumer = k -> System.out.println(i + j + k);} }

為了執行,lambda表達式需要訪問Foo的封閉實例及其封閉方法的值j。 因此,上述類的已廢止版本看起來類似于以下內容,其中invokedynamic指令由某些偽代碼表示:

class Foo {int i;void bar(int j) {Consumer consumer = <invokedynamic(this, j)>;}private /* non-static */ void lambda$foo$0(int j, int k) {System.out.println(this.i + j + k);} }

為了能夠調用lambda$foo$0 ,將封閉的Foo實例和j變量都傳遞到由invokedyanmic指令綁定的工廠。 然后,該工廠接收其所需的變量,以創建所生成類的實例。 然后,此生成的類如下所示:

class Foo$$Lambda$0 implements Consumer {private final Foo _this;private final int j;private Foo$$Lambda$0(Foo _this, int j) {this._this = _this;this.j = j;}private static Consumer get$Lambda(Foo _this, int j) {return new Foo$$Lambda$0(_this, j);}public void accept(Object value) { // type erasure_this.lambda$foo$0(_this, j, (Integer) value);} }

最終,生成的類的工廠方法通過一個由ConstantCallSite包含的方法句柄綁定到invokedynamic調用站點。 但是,如果lambda表達式是完全無狀態的,即它不需要訪問包含它的實例或方法,則LambdaMetafactory返回一個所謂的常量方法句柄,該句柄引用一個急切創建的生成類實例。 因此,此實例用作單例,以便每次到達lambda表達式的調用站點時使用。 顯然,此優化決策會影響您的應用程序的內存占用,并且在編寫lambda表達式時要牢記這一點。 同樣,沒有工廠方法被添加到無狀態lambda表達式的類中。

您可能已經注意到,lambda表達式的方法主體包含在一個私有方法中,該方法現在從另一個類中調用。 通常,這將導致非法訪問錯誤。 為了克服此限制,使用所謂的匿名類加載來加載生成的類。 僅當通過傳遞字節數組顯式加載類時,才可以應用匿名類加載。 另外,通常無法在用戶代碼中應用匿名類加載,因為匿名類加載已隱藏在Java類庫的內部類中。 當使用匿名類加載來加載類時,它會收到一個其繼承其完整安全上下文的宿主類。 這涉及方法和字段訪問權限以及保護域,因此也可以為簽名的jar文件生成lambda表達式。 使用此方法,可以認為lambda表達式比匿名內部類更安全,因為從類外部永遠無法訪問私有方法。

內幕:lambda表格

Lambda表單是虛擬機如何執行MethodHandles的實現細節。 由于其名稱,lambda形式經常與lambda表達式混淆。 取而代之的是,lambda表單受lambda演算的啟發,并因此獲得了它們的名稱,而不是因為其在OpenJDK中實現lambda表達式的實際用法。

在OpenJDK 7的早期版本中,方法句柄可以兩種方式之一執行。 方法句柄要么直接呈現為字節碼,要么使用Java運行時提供的顯式匯編代碼進行分派。 字節碼呈現已應用于在Java類的整個生命周期中被認為是完全恒定的任何方法句柄。 但是,如果JVM無法證明該屬性,則通過將其分配給提供的匯編代碼來執行方法句柄。 不幸的是,由于Java的JIT編譯器無法優化匯編代碼,因此導致了非恒定的方法句柄調用,從而“降低了性能”。 由于這也會影響延遲綁定的lambda表達式,因此,這顯然不是令人滿意的解決方案。

引入LambdaForm來解決此問題。 粗略地說,lambda形式表示字節碼指令,如前所述,可以由JIT編譯器進行優化。 在OpenJDK中,今天,方法句柄通過LambdaForm表示MethodHandle的調用語義。 通過這種可優化的中間表示,非恒定MethodHandle的使用變得更加MethodHandle 。 實際上,甚至有可能看到字節碼編譯的LambdaForm在LambdaForm 。 只需將斷點放置在bootstrap方法內部或通過MethodHandle調用的方法內部。 斷點LambdaForm可以在調用堆棧中找到經過字節碼轉換的LambdaForm 。

為什么這對動態語言很重要

應該在Java虛擬機上執行的任何語言都必須轉換為Java字節碼。 顧名思義,Java字節碼與Java編程語言非常接近。 這包括為任何值定義嚴格類型的要求,并且在引入invokedynamic之前,需要一個方法調用來指定用于調度方法的顯式目標類。 查看以下JavaScript代碼,但是在將方法轉換為字節碼時無法指定任何信息:

function (foo) {foo.bar(); }

通過使用invokedynamic調用站點,可以將方法的調度程序的標識延遲到運行時,此外,在需要更正先前決策的情況下,可以重新綁定調用目標。 以前,使用具有所有性能缺陷的反射API是實現動態語言的唯一真正選擇。

因此,invokedynamic指令的真正受益者是動態編程語言。 添加指令是使字節碼格式與Java編程語言保持一致的第一步,這使JVM即使對于動態語言也成為強大的運行時。 而且,正如lambda表達式所證明的那樣,這種將重點放在將動態語言托管在JVM上的重點并沒有干擾Java語言的發展。 相反,Java編程語言是從這些努力中獲得的。

翻譯自: https://www.javacodegeeks.com/2015/04/dismantling-invokedynamic.html

小度拆卸

總結

以上是生活随笔為你收集整理的小度拆卸_拆卸invokedynamic的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。