中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

怎么做網(wǎng)上賭博的網(wǎng)站寧波網(wǎng)絡(luò)推廣平臺(tái)

怎么做網(wǎng)上賭博的網(wǎng)站,寧波網(wǎng)絡(luò)推廣平臺(tái),搜索引擎推廣案例,網(wǎng)絡(luò)營(yíng)銷策略論文一、lambda 代碼 & 反編譯 原始Java代碼 假設(shè)我們有以下簡(jiǎn)單的Java程序,它使用Lambda表達(dá)式來遍歷并打印一個(gè)字符串列表: import java.util.Arrays; import java.util.List;public class LambdaExample {public static void main(String[] args) {…

一、lambda 代碼 & 反編譯

原始Java代碼
假設(shè)我們有以下簡(jiǎn)單的Java程序,它使用Lambda表達(dá)式來遍歷并打印一個(gè)字符串列表:

import java.util.Arrays;
import java.util.List;public class LambdaExample {public static void main(String[] args) {List<String> items = Arrays.asList("Apple", "Banana", "Cherry");items.forEach(item -> System.out.println(item));}
}
public interface Iterable<T> {default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}
}

CFR反編譯結(jié)果:

/** Decompiled with CFR 0.152.*/
import java.lang.invoke.LambdaMetafactory;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;public class LambdaExample {public static void main(String[] stringArray) {List<String> list = Arrays.asList("Apple", "Banana", "Cherry");list.forEach((Consumer<String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)());}private static /* synthetic */ void lambda$main$0(String string) {System.out.println(string);}
}

這是程序的主方法,它創(chuàng)建了一個(gè)包含三個(gè)字符串的列表,并使用forEach方法遍歷這個(gè)列表。在原始的Java代碼中,這里很可能使用了一個(gè)Lambda表達(dá)式來打印列表中的每個(gè)元素。在反編譯的代碼中,Lambda表達(dá)式被轉(zhuǎn)換成了對(duì)LambdaMetafactory.metafactory方法的調(diào)用,這個(gè)方法在運(yùn)行時(shí)動(dòng)態(tài)生成了一個(gè)實(shí)現(xiàn)了Consumer接口的類的實(shí)例。因?yàn)閒orEach方法入?yún)⒕褪且粋€(gè)函數(shù)式接口Consumer<? super T>,即:最終返回Consumer實(shí)例對(duì)象

二、反編譯代碼詳解

2.1 LambdaMetafactory lambda元工廠類 方法:metafactory

/*** 為了支持Java編程語言中的ambda表達(dá)式和方法引用表達(dá)式特性,* 本方法提供了一種簡(jiǎn)便的方式來創(chuàng)建實(shí)現(xiàn)一個(gè)或多個(gè)接口的“函數(shù)對(duì)象”。這些函數(shù)對(duì)象是通過委托給一個(gè)提供的{@link MethodHandle},* 在適當(dāng)?shù)念愋瓦m配和參數(shù)的部分求值之后實(shí)現(xiàn)的。通常作為{@code invokedynamic}調(diào)用點(diǎn)的<em>引導(dǎo)方法</em>使用。** <p>這是標(biāo)準(zhǔn)的、簡(jiǎn)化的元工廠方法;通過{@link #altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}* 提供了額外的靈活性。關(guān)于此方法的行為的一般描述,請(qǐng)參見{@link LambdaMetafactory}。** <p>當(dāng)從此方法返回的{@code CallSite}的目標(biāo)被調(diào)用時(shí),生成的函數(shù)對(duì)象是實(shí)現(xiàn)由{@code invokedType}的返回類型命名的接口的類的實(shí)例,* 聲明了一個(gè)具有由{@code invokedName}和{@code samMethodType}給出的名稱和簽名的方法。它還可能覆蓋來自{@code Object}的額外方法。** @param caller 表示具有調(diào)用者訪問權(quán)限的查找上下文。當(dāng)與{@code invokedynamic}一起使用時(shí),這由VM自動(dòng)堆疊。* @param invokedName 要實(shí)現(xiàn)的方法的名稱。當(dāng)與{@code invokedynamic}一起使用時(shí),這由{@code InvokeDynamic}結(jié)構(gòu)的{@code NameAndType}提供,并由VM自動(dòng)堆疊。* @param invokedType {@code CallSite}的預(yù)期簽名。參數(shù)類型代表捕獲變量的類型;返回類型是要實(shí)現(xiàn)的接口。當(dāng)與{@code invokedynamic}一起使用時(shí),這由{@code InvokeDynamic}結(jié)構(gòu)的{@code NameAndType}提供,并由VM自動(dòng)堆疊。如果實(shí)現(xiàn)方法是實(shí)例方法并且此簽名有任何參數(shù),則調(diào)用簽名中的第一個(gè)參數(shù)必須對(duì)應(yīng)于接收者。* @param samMethodType 函數(shù)對(duì)象要實(shí)現(xiàn)的方法的簽名和返回類型。* @param implMethod 描述應(yīng)在調(diào)用時(shí)調(diào)用的實(shí)現(xiàn)方法的直接方法句柄(適當(dāng)?shù)剡m配參數(shù)類型、返回類型,并將捕獲的參數(shù)前置到調(diào)用參數(shù)中)。* @param instantiatedMethodType 應(yīng)在調(diào)用時(shí)動(dòng)態(tài)強(qiáng)制執(zhí)行的簽名和返回類型。這可能與{@code samMethodType}相同,或可能是其特化版本。* @return 一個(gè)CallSite,其目標(biāo)可用于執(zhí)行捕獲,生成由{@code invokedType}命名的接口的實(shí)例* @throws LambdaConversionException 如果違反了{(lán)@link LambdaMetafactory}中描述的任何鏈接不變量*/public static CallSite metafactory(MethodHandles.Lookup caller,String invokedName,MethodType invokedType,MethodType samMethodType,MethodHandle implMethod,MethodType instantiatedMethodType)throws LambdaConversionException {// 創(chuàng)建一個(gè)內(nèi)部類Lambda元工廠實(shí)例,用于生成和驗(yàn)證lambda表達(dá)式的實(shí)現(xiàn)AbstractValidatingLambdaMetafactory mf;mf = new InnerClassLambdaMetafactory(caller, invokedType,invokedName, samMethodType,implMethod, instantiatedMethodType,false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);// 驗(yàn)證元工廠方法的參數(shù)是否符合要求mf.validateMetafactoryArgs();// 構(gòu)建并返回一個(gè)CallSite,它是lambda表達(dá)式或方法引用的動(dòng)態(tài)調(diào)用點(diǎn)return mf.buildCallSite();}

java.lang.invoke.LambdaMetafactory#metafactory 詳解

metafactory是LambdaMetafactory中的一個(gè)靜態(tài)方法,用于支持lambda表達(dá)式和方法引用表達(dá)式的動(dòng)態(tài)實(shí)現(xiàn)。它是LambdaMetafactory類的一部分,該類是Java語言中l(wèi)ambda表達(dá)式和方法引用的底層支持機(jī)制。下面是對(duì)這段代碼的詳細(xì)解釋:

  1. 方法的作用和目的
    這個(gè)方法的目的是為了動(dòng)態(tài)創(chuàng)建一個(gè)實(shí)現(xiàn)特定接口的"函數(shù)對(duì)象"。這個(gè)函數(shù)對(duì)象通過委托給一個(gè)提供的MethodHandle(方法句柄),在適當(dāng)?shù)念愋瓦m配和參數(shù)的部分求值后,實(shí)現(xiàn)一個(gè)或多個(gè)接口。這通常用作invokedynamic調(diào)用點(diǎn)的引導(dǎo)方法(bootstrap method),以支持Java編程語言中的lambda表達(dá)式和方法引用表達(dá)式特性。

  2. 參數(shù)

    • 方法接收六個(gè)參數(shù):callerinvokedName、invokedTypesamMethodType、implMethodinstantiatedMethodType。
      • caller:調(diào)用者,這個(gè)例子中就是LambdaExample類的MethodHandles.Lookup實(shí)例(每個(gè)類都可以通過調(diào)用MethodHandles.lookup()靜態(tài)方法來獲取一個(gè)與該類對(duì)應(yīng)的MethodHandles.Lookup實(shí)例。這個(gè)Lookup實(shí)例代表了調(diào)用者的類,并且擁有創(chuàng)建方法句柄(MethodHandle)的權(quán)限,這些方法句柄可以訪問調(diào)用者類中的成員,包括私有成員。),這個(gè)實(shí)例具有訪問LambdaExample類中所有成員的權(quán)限。該參數(shù)是jvm自動(dòng)填充。
      • invokedName:被調(diào)用方法的名稱,在這個(gè)例子中,forEach方法接受一個(gè)java.util.function.Consumer類型的參數(shù)。Consumer接口定義了一個(gè)名為accept的抽象方法。因此,在這個(gè)上下文中,invokedName將是accept。 該參數(shù)是jvm自動(dòng)填充。
      • invokedType:被調(diào)用方法的簽名類型,這是一個(gè)java.lang.invoke.MethodType對(duì)象。在lambda表達(dá)式或方法引用的上下文中,invokedType描述了期望的調(diào)用點(diǎn)的簽名,包括參數(shù)類型和返回類型。具體來說,invokedType參數(shù)定義了:
        ①調(diào)用點(diǎn)期望的參數(shù)類型,這些參數(shù)類型代表了lambda表達(dá)式或方法引用捕獲的變量類型(如果有的話)。
        ②調(diào)用點(diǎn)期望的返回類型,這通常是一個(gè)函數(shù)式接口的類型,lambda表達(dá)式或方法引用將會(huì)生成一個(gè)實(shí)現(xiàn)了這個(gè)接口的對(duì)象。 在這個(gè)例子中,forEach方法接受一個(gè)java.util.function.Consumer類型的參數(shù)。Consumer接口定義了一個(gè)接受單個(gè)String參數(shù)且返回void的accept方法。因此,在這個(gè)上下文中,invokedType將是Consumer的方法簽名,即接受一個(gè)String參數(shù)且返回void的方法類型。 該參數(shù)是jvm自動(dòng)填充。
      • samMethodType:java.lang.invoke.LambdaMetafactory#metafactory方法的參數(shù)samMethodType指的是單抽象方法(Single Abstract Method, SAM)的方法類型。這是一個(gè)java.lang.invoke.MethodType對(duì)象,它描述了目標(biāo)函數(shù)式接口中單個(gè)抽象方法的簽名,包括參數(shù)類型和返回類型。
        在使用lambda表達(dá)式或方法引用時(shí),通常會(huì)有一個(gè)函數(shù)式接口作為目標(biāo)類型。函數(shù)式接口是指僅定義一個(gè)抽象方法的接口。samMethodType參數(shù)正是用來描述這個(gè)抽象方法的簽名。在這個(gè)例子中,forEach方法接受一個(gè)java.util.function.Consumer類型的參數(shù)。Consumer是一個(gè)函數(shù)式接口,它定義了一個(gè)名為accept的抽象方法,該方法接受一個(gè)類型為T的參數(shù)并返回void。對(duì)于這個(gè)特定的例子,T是String類型,因此accept方法的簽名是(String) -> void。
      • implMethod:java.lang.invoke.LambdaMetafactory#metafactory方法的參數(shù)implMethod指的是實(shí)現(xiàn)方法的MethodHandle。這個(gè)MethodHandle代表了lambda表達(dá)式或方法引用的實(shí)際實(shí)現(xiàn)體。在lambda表達(dá)式或方法引用被轉(zhuǎn)換成動(dòng)態(tài)方法調(diào)用時(shí),implMethod就是那個(gè)被調(diào)用以執(zhí)行具體操作的方法。
        具體來說,implMethod參數(shù)描述了:
        ①方法的實(shí)現(xiàn):這是lambda表達(dá)式或方法引用中定義的邏輯的實(shí)際代碼位置。
        ②方法的簽名:通過MethodHandle的類型,它還隱含地指定了方法的參數(shù)類型和返回類型。
        在這個(gè)例子中,lambda表達(dá)式item -> System.out.println(item)對(duì)應(yīng)的implMethod就是System.out.println(String)方法的MethodHandle。這個(gè)MethodHandle指向PrintStream類中的println(String)方法,這是因?yàn)镾ystem.out是一個(gè)PrintStream的實(shí)例。
      • instantiatedMethodType:指的是實(shí)例化方法的類型。這是一個(gè)java.lang.invoke.MethodType對(duì)象,它描述了在生成的lambda表達(dá)式或方法引用的實(shí)例中,目標(biāo)方法的簽名。具體來說,它定義了lambda表達(dá)式或方法引用在實(shí)現(xiàn)函數(shù)式接口時(shí),該接口中抽象方法的調(diào)用簽名,包括參數(shù)類型和返回類型。在這個(gè)例子中,forEach方法接受一個(gè)java.util.function.Consumer類型的參數(shù)。Consumer是一個(gè)函數(shù)式接口,它定義了一個(gè)名為accept的抽象方法,該方法接受一個(gè)類型為String的參數(shù)并返回void。因此,對(duì)于這個(gè)特定的例子,instantiatedMethodType將是描述accept方法簽名的MethodType對(duì)象,即接受一個(gè)String參數(shù)且返回void的方法類型。
  3. 邏輯解釋

    • AbstractValidatingLambdaMetafactory mf;:聲明一個(gè)AbstractValidatingLambdaMetafactory類型的變量mf,這是一個(gè)抽象類,用于驗(yàn)證lambda工廠的參數(shù)。
    • mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);:實(shí)例化mfInnerClassLambdaMetafactory對(duì)象,這個(gè)對(duì)象負(fù)責(zé)創(chuàng)建實(shí)現(xiàn)特定接口的函數(shù)對(duì)象。傳入的參數(shù)包括調(diào)用者的查找上下文、被調(diào)用方法的名稱和類型、SAM(Single Abstract Method)接口的方法類型、實(shí)現(xiàn)方法的方法句柄、以及實(shí)例化方法的類型。false表示這個(gè)lambda對(duì)象不需要是可序列化的,EMPTY_CLASS_ARRAYEMPTY_MT_ARRAY分別表示沒有額外的接口和方法類型需要被實(shí)現(xiàn)或適配。
    • mf.validateMetafactoryArgs();:調(diào)用mfvalidateMetafactoryArgs方法進(jìn)行參數(shù)驗(yàn)證,確保傳入的參數(shù)滿足lambda表達(dá)式和方法引用的鏈接要求。
    • return mf.buildCallSite();:調(diào)用mfbuildCallSite方法構(gòu)建并返回一個(gè)CallSite對(duì)象,這個(gè)對(duì)象的目標(biāo)可以用來執(zhí)行捕獲,生成實(shí)現(xiàn)了指定接口的實(shí)例。

    CallSite是Java中的一個(gè)類,它代表了一個(gè)動(dòng)態(tài)方法調(diào)用點(diǎn)。在Java7的動(dòng)態(tài)語言支持中,CallSite提供了一種機(jī)制,允許方法調(diào)用的行為在運(yùn)行時(shí)動(dòng)態(tài)改變,而不是在編譯時(shí)靜態(tài)確定。這對(duì)于實(shí)現(xiàn)動(dòng)態(tài)類型語言或支持某些高級(jí)動(dòng)態(tài)特性的靜態(tài)類型語言(如Java中的lambda表達(dá)式和方法引用)非常有用。CallSite對(duì)象包含一個(gè)稱為目標(biāo)(target)的MethodHandle,這個(gè)MethodHandle實(shí)際上定義了調(diào)用點(diǎn)的行為。當(dāng)對(duì)CallSite進(jìn)行方法調(diào)用時(shí),實(shí)際上是在調(diào)用其目標(biāo)MethodHandle。
    Java中的CallSite幾種不同的類型,包括:

    • MethodHandleNatives.CallSite:這是最基本CallSite,直接關(guān)聯(lián)一個(gè)MethodHandle作為其調(diào)用目標(biāo)。
    • ConstantCallSite:一個(gè)不可變CallSite,其目標(biāo)在構(gòu)造時(shí)被設(shè)置,并且之后不能改變。這對(duì)于那些不需要改變的方法調(diào)用非常有用,可以提供更好的性能。
    • MutableCallSite:一個(gè)可變CallSite,允許改變其目標(biāo)MethodHandle。這對(duì)于需要根據(jù)運(yùn)行時(shí)條件改變調(diào)用行為的情況非常有用。
    • VolatileCallSite:類似于MutableCallSite,但是對(duì)目標(biāo)MethodHandle的更新是volatile的,確保了線程安全。

    CallSiteMethodHandle是Java對(duì)動(dòng)態(tài)語言特性的支持的核心部分,它們使得Java能夠以更靈活和動(dòng)態(tài)的方式處理方法調(diào)用,支持如lambda表達(dá)式和方法引用等現(xiàn)代編程特性。

    metafactory方法返回的調(diào)用點(diǎn)是CallSite的一個(gè)實(shí)例。具體來說,根據(jù)LambdaMetafactory的實(shí)現(xiàn),它通常返回的是ConstantCallSite的一個(gè)實(shí)例。ConstantCallSiteCallSite的一個(gè)子類,它表示一個(gè)不可變的調(diào)用點(diǎn)。一旦ConstantCallSite的目標(biāo)方法句柄(MethodHandle)被設(shè)置,它就不會(huì)改變。這種特性使得ConstantCallSite非常適合于lambda表達(dá)式和方法引用的場(chǎng)景,因?yàn)檫@些場(chǎng)景中的目標(biāo)方法通常在創(chuàng)建時(shí)就已經(jīng)確定,并且在其生命周期內(nèi)不需要改變。
    ·
    LambdaMetafactory的上下文中,metafactory方法通過動(dòng)態(tài)生成的類來實(shí)現(xiàn)函數(shù)接口,并創(chuàng)建一個(gè)指向這個(gè)實(shí)現(xiàn)的方法句柄(MethodHandle)。然后,這個(gè)方法句柄被用作ConstantCallSite的目標(biāo),從而創(chuàng)建一個(gè)CallSite實(shí)例。這個(gè)CallSite實(shí)例在被調(diào)用時(shí),會(huì)直接調(diào)用那個(gè)實(shí)現(xiàn)了函數(shù)接口的動(dòng)態(tài)生成類的方法。

這段代碼通過動(dòng)態(tài)創(chuàng)建和配置CallSite對(duì)象,支持了Java中l(wèi)ambda表達(dá)式和方法引用表達(dá)式的動(dòng)態(tài)實(shí)現(xiàn)。

2.2、InnerClassLambdaMetafactory

InnerClassLambdaMetafactory構(gòu)造函數(shù)、buildCallSite構(gòu)建CallSite調(diào)用點(diǎn)

 /*** 構(gòu)造函數(shù):創(chuàng)建一個(gè)內(nèi)部類Lambda元工廠的實(shí)例。* 該構(gòu)造函數(shù)用于支持標(biāo)準(zhǔn)情況以及允許序列化或橋接等不常見選項(xiàng)。** @param caller 由VM自動(dòng)堆疊;代表具有調(diào)用者訪問權(quán)限的查找上下文。* @param invokedType 由VM自動(dòng)堆疊;被調(diào)用方法的簽名,包括返回的lambda對(duì)象的預(yù)期靜態(tài)類型,*                    以及l(fā)ambda捕獲參數(shù)的靜態(tài)類型。如果實(shí)現(xiàn)方法是實(shí)例方法,調(diào)用簽名的第一個(gè)參數(shù)將對(duì)應(yīng)于接收者。* @param samMethodName 轉(zhuǎn)換為lambda或方法引用的函數(shù)接口中的方法名稱,表示為String。* @param samMethodType 轉(zhuǎn)換為lambda或方法引用的函數(shù)接口中的方法類型,表示為MethodType。* @param implMethod 應(yīng)當(dāng)被調(diào)用的實(shí)現(xiàn)方法(適當(dāng)調(diào)整參數(shù)類型、返回類型和捕獲參數(shù)后),當(dāng)調(diào)用結(jié)果函數(shù)接口實(shí)例的方法時(shí)。* @param instantiatedMethodType 在從捕獲站點(diǎn)實(shí)例化類型變量后,主要函數(shù)接口方法的簽名。* @param isSerializable lambda是否應(yīng)該是可序列化的?如果設(shè)置,目標(biāo)類型或一個(gè)附加的SAM類型必須擴(kuò)展{@code Serializable}。* @param markerInterfaces lambda對(duì)象應(yīng)該實(shí)現(xiàn)的附加接口。* @param additionalBridges 額外的簽名,這些簽名將被橋接到實(shí)現(xiàn)方法。* @throws LambdaConversionException 如果違反了元工廠協(xié)議的任何不變量。*/public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,MethodType invokedType,String samMethodName,MethodType samMethodType,MethodHandle implMethod,MethodType instantiatedMethodType,boolean isSerializable,Class<?>[] markerInterfaces,MethodType[] additionalBridges)throws LambdaConversionException {// 調(diào)用父類構(gòu)造函數(shù),初始化基本參數(shù)super(caller, invokedType, samMethodName, samMethodType,implMethod, instantiatedMethodType,isSerializable, markerInterfaces, additionalBridges);// 初始化實(shí)現(xiàn)方法的類名,將'.'替換為'/'implMethodClassName = implDefiningClass.getName().replace('.', '/');// 初始化實(shí)現(xiàn)方法的名稱implMethodName = implInfo.getName();// 初始化實(shí)現(xiàn)方法的描述符implMethodDesc = implMethodType.toMethodDescriptorString();// 初始化實(shí)現(xiàn)方法返回類型的類implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)? implDefiningClass: implMethodType.returnType();// 初始化生成類構(gòu)造函數(shù)的類型constructorType = invokedType.changeReturnType(Void.TYPE);// 生成并初始化lambda類的名稱lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();// 【重要??????????】初始化ASM類寫入器cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);// 初始化構(gòu)造函數(shù)參數(shù)名稱和描述符數(shù)組int parameterCount = invokedType.parameterCount();if (parameterCount > 0) {// 初始化參數(shù)名和參數(shù)描述數(shù)組,大小為方法參數(shù)的數(shù)量argNames = new String[parameterCount];argDescs = new String[parameterCount];// 遍歷所有參數(shù),生成參數(shù)名和參數(shù)描述for (int i = 0; i < parameterCount; i++) {// 為每個(gè)參數(shù)生成一個(gè)唯一的名稱,格式為"arg$序號(hào)"argNames[i] = "arg$" + (i + 1);// 使用BytecodeDescriptor工具類將參數(shù)類型轉(zhuǎn)換為字符串描述形式argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));}} else {// 當(dāng)調(diào)用類型參數(shù)計(jì)數(shù)為0時(shí),初始化參數(shù)名和參數(shù)描述數(shù)組為空字符串?dāng)?shù)組argNames = argDescs = EMPTY_STRING_ARRAY;}}/*** 構(gòu)建CallSite。生成實(shí)現(xiàn)功能接口的類文件,定義類,如果沒有參數(shù)則創(chuàng)建類的實(shí)例,* 該實(shí)例將由CallSite返回,否則,生成的句柄將調(diào)用類的構(gòu)造函數(shù)。** @return CallSite,調(diào)用時(shí),將返回一個(gè)功能接口的實(shí)例* @throws ReflectiveOperationException 反射操作異常* @throws LambdaConversionException 如果沒有找到正確形式的功能接口*/@OverrideCallSite buildCallSite() throws LambdaConversionException {// 生成實(shí)現(xiàn)了函數(shù)接口的內(nèi)部類final Class<?> innerClass = spinInnerClass();// 如果調(diào)用類型沒有參數(shù),即無需捕獲的變量if (invokedType.parameterCount() == 0) {// 通過反射獲取一個(gè)內(nèi)部類的所有構(gòu)造函數(shù),并在只有一個(gè)構(gòu)造函數(shù)的情況下,將這個(gè)唯一的構(gòu)造函數(shù)設(shè)置為可訪問的。final Constructor<?>[] ctrs = AccessController.doPrivileged(new PrivilegedAction<Constructor<?>[]>() {@Overridepublic Constructor<?>[] run() {// 返回了innerClass(內(nèi)部類)的所有構(gòu)造函數(shù),包括私有的。Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();if (ctrs.length == 1) {// 如果只有一個(gè)構(gòu)造函數(shù),設(shè)置為可訪問ctrs[0].setAccessible(true);}return ctrs;}});// 確保只有一個(gè)構(gòu)造函數(shù)if (ctrs.length != 1) {throw new LambdaConversionException("Expected one lambda constructor for "+ innerClass.getCanonicalName() + ", got " + ctrs.length);}try {// 通過構(gòu)造函數(shù)實(shí)例化對(duì)象Object inst = ctrs[0].newInstance();// 創(chuàng)建并返回一個(gè)持有l(wèi)ambda對(duì)象的ConstantCallSitereturn new ConstantCallSite(MethodHandles.constant(samBase, inst));}catch (ReflectiveOperationException e) {throw new LambdaConversionException("Exception instantiating lambda object", e);}} else {// 如果有參數(shù),需要通過靜態(tài)方法來創(chuàng)建CallSitetry {// 確保類已經(jīng)被完全初始化UNSAFE.ensureClassInitialized(innerClass);// 查找靜態(tài)方法并創(chuàng)建CallSitereturn new ConstantCallSite(MethodHandles.Lookup.IMPL_LOOKUP.findStatic(innerClass, NAME_FACTORY, invokedType));}catch (ReflectiveOperationException e) {throw new LambdaConversionException("Exception finding constructor", e);}}}/*** 生成并返回一個(gè)實(shí)現(xiàn)了功能接口的類文件。** @implNote 生成的類文件不包含SAM方法可能存在的異常簽名信息,* 旨在減少類文件大小。這是無害的,因?yàn)橐褭z查的異常會(huì)被擦除,* 沒有人會(huì)針對(duì)這個(gè)類文件進(jìn)行編譯,我們不保證lambda對(duì)象的反射屬性。** @return 實(shí)現(xiàn)了功能接口的類* @throws LambdaConversionException 如果沒有找到正確形式的功能接口*/private Class<?> spinInnerClass() throws LambdaConversionException {// 構(gòu)建一個(gè)字符串?dāng)?shù)組 interfaces,該數(shù)組包含了要實(shí)現(xiàn)的接口的內(nèi)部名稱(即將.替換為/的全限定類名),同時(shí)確保沒有重復(fù)的接口,并檢查是否意外地實(shí)現(xiàn)了 Serializable 接口。String[] interfaces;// 獲取函數(shù)式接口的內(nèi)部名稱,將.替換為/。String samIntf = samBase.getName().replace('.', '/');// 檢查基礎(chǔ)函數(shù)式接口是否意外實(shí)現(xiàn)了 Serializable 接口。boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);// 如果沒有額外的標(biāo)記接口,直接使用函數(shù)式接口的內(nèi)部名稱作為 interfaces 的唯一元素。if (markerInterfaces.length == 0) {interfaces = new String[]{samIntf};} else {// 如果 markerInterfaces 非空,確保沒有重復(fù)的接口(ClassFormatError),使用 LinkedHashSet 來存儲(chǔ)接口名稱,確保不會(huì)有重復(fù)。Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);// 將函數(shù)式接口的內(nèi)部名稱添加到集合中itfs.add(samIntf);// 遍歷額外的標(biāo)記接口,將它們的內(nèi)部名稱添加到集合中,并檢查是否意外實(shí)現(xiàn)了 Serializable 接口。for (Class<?> markerInterface : markerInterfaces) {itfs.add(markerInterface.getName().replace('.', '/'));accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);}// 將接口名稱集合轉(zhuǎn)換為字符串?dāng)?shù)組。interfaces = itfs.toArray(new String[itfs.size()]);}/**cw 是 ClassWriter 的實(shí)例,它是 ASM(一個(gè)通用的 Java 字節(jié)碼操作和分析框架)庫(kù)中的一個(gè)類。ClassWriter 用于動(dòng)態(tài)生成類或接口的二進(jìn)制字節(jié)碼。在上下文中,cw 被用來構(gòu)建和定義一個(gè)新的類,這個(gè)類是在運(yùn)行時(shí)動(dòng)態(tài)生成的,用于實(shí)現(xiàn)特定的功能接口,通常是為了支持 Java 中的 lambda 表達(dá)式。
通過調(diào)用 ClassWriter 的方法,如 visit、visitMethod 和 visitField,可以分別定義類的基本信息、方法和字段。最終,通過調(diào)用 cw.toByteArray() 方法,可以獲取到這個(gè)動(dòng)態(tài)生成的類的字節(jié)碼數(shù)組,這個(gè)數(shù)組可以被加載到 JVM 中,從而創(chuàng)建出一個(gè)新的類實(shí)例。*/// 定義了一個(gè)類,這個(gè)類是final和synthetic的,繼承自O(shè)bject類,并實(shí)現(xiàn)了interfaces數(shù)組中指定的接口。lambdaClassName是這個(gè)類的名稱。// 其中:// 	ACC_FINAL 表示這個(gè)類是final的//	ACC_SYNTHETIC 表示這個(gè)類是synthetic的,synthetic標(biāo)記表明這個(gè)類是由編譯器自動(dòng)生成的,而非直接來自源代碼。//	lambdaClassName 是動(dòng)態(tài)生成的類名cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,lambdaClassName, null,JAVA_LANG_OBJECT, interfaces);// 生成構(gòu)造函數(shù)中要填充的最終字段for (int i = 0; i < argDescs.length; i++) {// 生成一個(gè)private final字段來存儲(chǔ)這些參數(shù)的值。FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,argNames[i],argDescs[i],null, null);/**這行代碼的作用是結(jié)束一個(gè)字段的訪問。在ASM中,每當(dāng)開始定義一個(gè)新的字段時(shí),都會(huì)通過調(diào)用visitField方法返回一個(gè)FieldVisitor對(duì)象,通過這個(gè)對(duì)象可以定義字段的屬性。當(dāng)字段的定義結(jié)束時(shí),需要調(diào)用visitEnd方法來標(biāo)志這個(gè)過程的結(jié)束。*/                                fv.visitEnd();}// 生成構(gòu)造函數(shù)generateConstructor();// 判斷是檢查invokedType(lambda表達(dá)式的目標(biāo)類型)是否有參數(shù)。if (invokedType.parameterCount() != 0) {// 這個(gè)方法的作用是生成工廠方法。工廠方法是一個(gè)特殊的方法,用于動(dòng)態(tài)生成并返回實(shí)現(xiàn)了函數(shù)式接口的類的實(shí)例。這個(gè)過程通常涉及到字節(jié)碼的生成和類的加載。generateFactory();}/**這行代碼通過調(diào)用 ClassWriter 的 visitMethod 方法創(chuàng)建了一個(gè)新的方法。這個(gè)方法的訪問級(jí)別是 public,方法名是 samMethodName,這是一個(gè)從外部傳入的參數(shù),表示要實(shí)現(xiàn)的SAM接口中的方法名。samMethodType.toMethodDescriptorString() 將方法的簽名轉(zhuǎn)換為字符串形式,用于定義方法的參數(shù)類型和返回類型。最后兩個(gè) null 參數(shù)分別表示這個(gè)方法的簽名和異常,這里不使用這些高級(jí)特性,所以傳入 null。*/MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,samMethodType.toMethodDescriptorString(), null, null);// 這行代碼給剛才創(chuàng)建的方法添加了一個(gè)注解 LambdaForm$Hidden。這個(gè)注解是內(nèi)部使用的,用于標(biāo)記這個(gè)方法不應(yīng)該被外部調(diào)用或者看到。true 參數(shù)表示這個(gè)注解是在運(yùn)行時(shí)可見的。mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);// 這行代碼實(shí)際上是生成方法體的關(guān)鍵步驟。它創(chuàng)建了一個(gè) ForwardingMethodGenerator 對(duì)象,這個(gè)對(duì)象負(fù)責(zé)生成方法體的字節(jié)碼。generate 方法接受一個(gè) MethodType 對(duì)象 samMethodType 作為參數(shù),這個(gè)對(duì)象描述了SAM接口方法的參數(shù)類型和返回類型。generate 方法根據(jù)這個(gè)信息,動(dòng)態(tài)生成字節(jié)碼,這些字節(jié)碼實(shí)現(xiàn)了將調(diào)用轉(zhuǎn)發(fā)到實(shí)際的目標(biāo)方法上。new ForwardingMethodGenerator(mv).generate(samMethodType);/**這段代碼的主要作用是為了生成橋接方法(Bridge Methods),這些方法用于處理泛型擦除后的類型不匹配問題。在Java中,泛型信息在編譯時(shí)會(huì)被擦除,而橋接方法則用于在運(yùn)行時(shí)保持類型的正確性。這段代碼是在動(dòng)態(tài)生成的類中添加這些橋接方法的過程。*/// additionalBridges 是一個(gè)包含了需要生成橋接方法的 MethodType 對(duì)象的數(shù)組。if (additionalBridges != null) {for (MethodType mt : additionalBridges) {// 為每個(gè)橋接方法類型生成方法:通過調(diào)用 cw.visitMethod 方法生成橋接方法。這里的 cw 是一個(gè) ClassWriter 對(duì)象,用于動(dòng)態(tài)生成類的字節(jié)碼。ACC_PUBLIC|ACC_BRIDGE 是方法的訪問標(biāo)志,表示這是一個(gè)公開的橋接方法。samMethodName 是要實(shí)現(xiàn)的函數(shù)式接口的方法名,mt.toMethodDescriptorString() 將方法類型轉(zhuǎn)換為方法描述符字符串,用于指定方法的簽名。mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,mt.toMethodDescriptorString(), null, null);// 添加方法注解:通過調(diào)用 mv.visitAnnotation 方法為生成的橋接方法添加注解。這里的注解是 "Ljava/lang/invoke/LambdaForm$Hidden;",表示這個(gè)方法是由lambda表達(dá)式生成的,不應(yīng)該被直接調(diào)用。mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);// 生成方法體:通過創(chuàng)建一個(gè)新的 ForwardingMethodGenerator 對(duì)象并調(diào)用其 generate 方法來生成橋接方法的方法體。這個(gè)方法體基本上是將調(diào)用轉(zhuǎn)發(fā)到實(shí)際的實(shí)現(xiàn)方法上。new ForwardingMethodGenerator(mv).generate(mt);}}/**這段代碼的作用是根據(jù)是否需要序列化,生成對(duì)應(yīng)的方法。具體來說,如果需要生成的類是可序列化的,則生成序列化友好的方法;如果不是故意的可序列化(即無意中成為可序列化的),則生成序列化敵對(duì)的方法。最后,調(diào)用 cw.visitEnd() 來完成類的定義。1.判斷是否需要序列化:通過 if (isSerializable) 判斷,如果 isSerializable 為 true,則表示需要生成的類是可序列化的,此時(shí)會(huì)調(diào)用 generateSerializationFriendlyMethods() 方法生成序列化友好的方法。2.判斷是否無意中成為可序列化:如果 isSerializable 為 false,則進(jìn)入 else if (accidentallySerializable) 判斷,accidentallySerializable 為 true 表示類無意中成為了可序列化的(例如,通過實(shí)現(xiàn)了某個(gè)可序列化的接口)。此時(shí)會(huì)調(diào)用 generateSerializationHostileMethods() 方法生成序列化敵對(duì)的方法,這可能是為了避免序列化帶來的潛在問題或性能影響。3.完成類的定義:無論是否需要序列化,最后都會(huì)執(zhí)行 cw.visitEnd(),這是ASM庫(kù)中的方法,用于完成類的定義。這一步是生成類文件的最后一步,標(biāo)志著類定義的結(jié)束。*/if (isSerializable)generateSerializationFriendlyMethods();else if (accidentallySerializable)generateSerializationHostileMethods();cw.visitEnd();// 這行代碼調(diào)用 ClassWriter 對(duì)象的 toByteArray 方法,將動(dòng)態(tài)生成的類轉(zhuǎn)換為字節(jié)碼數(shù)組。cw 是 ClassWriter 的實(shí)例,它負(fù)責(zé)生成類的字節(jié)碼。final byte[] classBytes = cw.toByteArray();/**這段代碼首先檢查 dumper 對(duì)象是否為 null。dumper 是一個(gè)可能用于將字節(jié)碼寫入文件的工具對(duì)象。如果 dumper 不為 null,則執(zhí)行以下步驟:1.使用 AccessController.doPrivileged 方法執(zhí)行一個(gè)特權(quán)操作。這是因?yàn)閷懭胛募赡苄枰囟ǖ臋?quán)限,特別是在啟用了安全管理器的環(huán)境中。2.在 doPrivileged 方法中,執(zhí)行一個(gè) PrivilegedAction,其 run 方法調(diào)用 dumper.dumpClass 方法,將類名 lambdaClassName 和字節(jié)碼數(shù)組 classBytes 傳遞給它,以便將字節(jié)碼寫入文件。3.doPrivileged 方法的第二個(gè)參數(shù)是 null,表示不使用特定的 AccessControlContext。4.第三和第四個(gè)參數(shù)是 FilePermission 和 PropertyPermission 對(duì)象,分別授予讀寫所有文件的權(quán)限和讀取用戶當(dāng)前目錄的權(quán)限。這些權(quán)限是執(zhí)行文件寫入操作所必需的。*/// 轉(zhuǎn)儲(chǔ)到文件if (dumper != null) {AccessController.doPrivileged(new PrivilegedAction<Void>() {@Overridepublic Void run() {dumper.dumpClass(lambdaClassName, classBytes);return null;}}, null,new FilePermission("<<ALL FILES>>", "read, write"),// 創(chuàng)建目錄可能需要它new PropertyPermission("user.dir", "read"));}/**1.代碼的作用下面這段代碼的作用是在運(yùn)行時(shí)動(dòng)態(tài)定義一個(gè)匿名類。UNSAFE.defineAnonymousClass 方法接收三個(gè)參數(shù):目標(biāo)類(targetClass),類的字節(jié)碼(classBytes),以及與類相關(guān)聯(lián)的常量池補(bǔ)丁(這里傳入的是 null)。2.代碼的結(jié)構(gòu)和邏輯2.1 targetClass:這是一個(gè) Class 對(duì)象,表示新定義的匿名類將與之關(guān)聯(lián)的上下文。通常,這個(gè)類是匿名類邏輯上的“宿主”類。2.2 classBytes:這是一個(gè)字節(jié)數(shù)組,包含了新匿名類的字節(jié)碼。這些字節(jié)碼通常是通過某種字節(jié)碼生成庫(kù)(如ASM)動(dòng)態(tài)生成的。2.3 null:這個(gè)參數(shù)是用于類定義時(shí)的常量池補(bǔ)丁,這里傳入 null 表示不需要進(jìn)行常量池的補(bǔ)丁。3.關(guān)鍵代碼塊或語句的解釋3.1 UNSAFE:這是 sun.misc.Unsafe 類的一個(gè)實(shí)例。Unsafe 類提供了一組底層、危險(xiǎn)的操作,通常不推薦在標(biāo)準(zhǔn)Java代碼中使用。但在某些特殊場(chǎng)景下,如動(dòng)態(tài)類生成、低級(jí)并發(fā)控制等,Unsafe 提供的功能是必需的。3.2 .defineAnonymousClass(targetClass, classBytes, null):這個(gè)方法調(diào)用是動(dòng)態(tài)定義匿名類的關(guān)鍵。它將 classBytes 中的字節(jié)碼轉(zhuǎn)換為一個(gè)Java類,并將這個(gè)新類與 targetClass 關(guān)聯(lián)起來。由于這個(gè)類是匿名的,它沒有正式的類名。傳入的 null 參數(shù)表示在定義類的過程中不需要對(duì)常量池進(jìn)行任何補(bǔ)丁操作。*/// 通過 Unsafe 類的 defineAnonymousClass 方法動(dòng)態(tài)定義了一個(gè)匿名類,這個(gè)類的字節(jié)碼由 classBytes 提供,而這個(gè)匿名類在邏輯上與 targetClass 關(guān)聯(lián)。return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);}

四、利用java.lang.invoke.InnerClassLambdaMetafactory#dumper 轉(zhuǎn)儲(chǔ)lambda文件

// 靜態(tài)初始化塊,用于初始化dumperstatic {/*** 獲取并設(shè)置代理類轉(zhuǎn)儲(chǔ)功能*/// 定義系統(tǒng)屬性的鍵名,用于控制是否轉(zhuǎn)儲(chǔ)內(nèi)部lambda代理類final String key = "jdk.internal.lambda.dumpProxyClasses";// 使用AccessController執(zhí)行特權(quán)操作,獲取系統(tǒng)屬性值String path = AccessController.doPrivileged(new GetPropertyAction(key), // 創(chuàng)建獲取屬性的動(dòng)作null, // 不指定AccessControlContextnew PropertyPermission(key , "read") // 指定所需的權(quán)限);// 根據(jù)獲取的路徑創(chuàng)建ProxyClassesDumper實(shí)例// 如果路徑為null,則不啟用轉(zhuǎn)儲(chǔ)功能dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);}

JVM參數(shù):jdk.internal.lambda.dumpProxyClasses
命令:java -Djdk.internal.lambda.dumpProxyClasses ClassName
轉(zhuǎn)儲(chǔ)得到內(nèi)部類
反編譯:java -jar cfr-0.152.jar LambdaExample.class --decodelambdas false

步驟一:源碼

import java.util.Arrays;
import java.util.List;public class LambdaExample {public static void main(String[] args) {List<String> items = Arrays.asList("Apple", "Banana", "Cherry");items.forEach(item -> System.out.println(item));}
}

步驟二:編譯,生成LambdaExample.class 文件

javac LambdaExample.java

步驟三:執(zhí)行java命令,生成文件:LambdaExample$$Lambda$1.class

java -Djdk.internal.lambda.dumpProxyClasses LambdaExample

這個(gè)命令是用來調(diào)試和分析 Java 中 lambda 表達(dá)式的底層實(shí)現(xiàn)的。具體解釋如下:

  1. -D 參數(shù):
    用于設(shè)置系統(tǒng)屬性。

  2. jdk.internal.lambda.dumpProxyClasses
    這是一個(gè)特殊的系統(tǒng)屬性,用于指示 JVM 將 lambda 表達(dá)式生成的代理類保存到磁盤。

  3. LambdaExample
    這是要運(yùn)行的包含 lambda 表達(dá)式的 Java 類名。

當(dāng)你運(yùn)行這個(gè)命令時(shí),JVM 會(huì)執(zhí)行以下操作:

  1. 運(yùn)行 LambdaExample 類。
  2. 對(duì)于該類中的每個(gè) lambda 表達(dá)式,JVM 會(huì)生成一個(gè)代理類。
  3. 這些生成的代理類會(huì)被保存到磁盤上,通常在當(dāng)前工作目錄下。

這個(gè)功能主要用于:

  • 分析 lambda 表達(dá)式的底層實(shí)現(xiàn)
  • 調(diào)試復(fù)雜的 lambda 表達(dá)式
  • 了解 JVM 如何處理和優(yōu)化 lambda 表達(dá)式

生成的代理類文件名通常遵循這樣的模式:
主類名$Lambda$序號(hào).class

步驟四:生成反編譯代碼:lambda內(nèi)部類

java -jar cfr-0.152.jar 'LambdaExample$$Lambda$1.class' --decodelambdas false

mac電腦,此處LambdaExample$$Lambda$1.class需要帶引號(hào),因?yàn)樵诿钚兄?#xff0c;$ 是一個(gè)特殊字符,用于引用變量。在這個(gè)上下文中,$$ 容易被解釋為當(dāng)前 shell 進(jìn)程的 PID(進(jìn)程ID),而不是文件名的一部分。所以你需要用引號(hào)將文件名括起來,這樣可以防止 shell 解釋 $ 字符。

/** Decompiled with CFR 0.152.*/
import java.lang.invoke.LambdaForm;
import java.util.function.Consumer;final class LambdaExample$$Lambda$1
implements Consumer {private LambdaExample$$Lambda$1() {}@LambdaForm.Hiddenpublic void accept(Object object) {LambdaExample.lambda$main$0((String)object);}
}

這段代碼是由Java編譯器為lambda表達(dá)式生成的內(nèi)部類。讓我們逐部分解析:

  1. final class LambdaExample$$Lambda$1

    • 這是一個(gè)自動(dòng)生成的內(nèi)部類,名稱中的 $$Lambda$1 表示它是為第一個(gè)lambda表達(dá)式生成的。
    • final 關(guān)鍵字表示這個(gè)類不能被繼承。
  2. implements Consumer

    • 這個(gè)類實(shí)現(xiàn)了 Consumer 接口,這是Java 8引入的函數(shù)式接口之一。
  3. private LambdaExample$$Lambda$1()

    • 這是一個(gè)私有構(gòu)造函數(shù),防止外部直接實(shí)例化這個(gè)類。
  4. @LambdaForm.Hidden

    • 這是一個(gè)內(nèi)部注解,用于標(biāo)記這個(gè)方法不應(yīng)該在堆棧跟蹤中顯示。
  5. public void accept(Object object)

    • 這是 Consumer 接口中定義的方法。
    • 方法接受一個(gè) Object 類型的參數(shù)。
  6. LambdaExample.lambda$main$0((String)object);

    • 這行代碼調(diào)用了 LambdaExample 類中的一個(gè)靜態(tài)方法 lambda$main$0。
    • 參數(shù) object 被強(qiáng)制轉(zhuǎn)換為 String 類型。

這個(gè)生成的類實(shí)際上是lambda表達(dá)式的一個(gè)"包裝器"。它將lambda表達(dá)式封裝成一個(gè)實(shí)現(xiàn)了 Consumer 接口的具體類。當(dāng)lambda表達(dá)式被調(diào)用時(shí),它會(huì)調(diào)用 LambdaExample 類中相應(yīng)的靜態(tài)方法(在這里是 lambda$main$0)。

這種實(shí)現(xiàn)方式允許Java在不使用匿名內(nèi)部類的情況下支持lambda表達(dá)式,從而提高了性能和減少了內(nèi)存使用。

三、結(jié)論

lambda 底層實(shí)現(xiàn)機(jī)制
1.lambda 表達(dá)式的本質(zhì):函數(shù)式接口的匿名子類的匿名對(duì)象
2.lambda表達(dá)式是語法糖

語法糖:編碼時(shí)是lambda簡(jiǎn)潔的表達(dá)式,在字節(jié)碼期,語法糖會(huì)被轉(zhuǎn)換為實(shí)際復(fù)雜的實(shí)現(xiàn)方式,含義不變;即編碼表面有個(gè)糖衣,在編譯期會(huì)被脫掉

Lambda表達(dá)式的編譯及運(yùn)行過程如下:

在這里插入圖片描述

編譯階段

  1. Lambda表達(dá)式識(shí)別

    • 編譯器識(shí)別Lambda表達(dá)式,將其轉(zhuǎn)換為靜態(tài)方法。
  2. 生成invokedynamic指令

    • 編譯器為每個(gè)Lambda表達(dá)式生成一個(gè)invokedynamic指令。
    • 指定LambdaMetafactory.metafactory或altMetafactory作為引導(dǎo)方法。
  3. ASM使用

    • 編譯器可能使用ASM庫(kù)生成或修改字節(jié)碼。

運(yùn)行階段

  1. 引導(dǎo)方法(Bootstrap Method)調(diào)用

    • 當(dāng)JVM首次遇到某個(gè)invokedynamic指令時(shí),它會(huì)調(diào)用指定的引導(dǎo)方法。對(duì)于Lambda表達(dá)式,這個(gè)引導(dǎo)方法通常是LambdaMetafactorymetafactory方法。
  2. LambdaMetafactory調(diào)用

    • 引導(dǎo)方法(通常是LambdaMetafactory.metafactory)被調(diào)用。
    • 接收參數(shù):MethodHandles.Lookup、函數(shù)式接口信息、Lambda方法信息等。
  3. 創(chuàng)建CallSite對(duì)象

    • 引導(dǎo)方法的任務(wù)之一是創(chuàng)建一個(gè)CallSite對(duì)象。CallSite是一個(gè)抽象類,它代表了一個(gè)動(dòng)態(tài)方法調(diào)用點(diǎn)。它的具體實(shí)現(xiàn)類(如ConstantCallSite)封裝了對(duì)特定方法的調(diào)用。
    • CallSite對(duì)象持有一個(gè)MethodHandle,這個(gè)MethodHandle指向?qū)嶋H要執(zhí)行的方法。對(duì)于Lambda表達(dá)式,這個(gè)方法是Lambda表達(dá)式轉(zhuǎn)換成的方法。
  4. 綁定MethodHandle

    • 在創(chuàng)建CallSite對(duì)象時(shí),引導(dǎo)方法會(huì)根據(jù)Lambda表達(dá)式的目標(biāo)類型和實(shí)際代碼,構(gòu)造一個(gè)MethodHandle。這個(gè)MethodHandle直接指向了包含Lambda表達(dá)式代碼的方法。
    • 然后,這個(gè)MethodHandle被綁定到CallSite對(duì)象上。這意味著,當(dāng)通過這個(gè)CallSite調(diào)用方法時(shí),實(shí)際上是通過綁定的MethodHandle來調(diào)用Lambda表達(dá)式對(duì)應(yīng)的方法。
  5. 返回CallSite對(duì)象

    • 引導(dǎo)方法返回CallSite對(duì)象給JVM。這個(gè)CallSite對(duì)象隨后被用于所有對(duì)該invokedynamic指令的調(diào)用。
    • 由于CallSite對(duì)象已經(jīng)綁定了對(duì)應(yīng)的MethodHandle,因此每次通過這個(gè)CallSite調(diào)用方法時(shí),都會(huì)直接調(diào)用到Lambda表達(dá)式對(duì)應(yīng)的方法,無需再次解析。
  6. InnerClassLambdaMetafactory使用
    InnerClassLambdaMetafactory用于動(dòng)態(tài)生成實(shí)現(xiàn)函數(shù)式接口的類。這個(gè)過程主要通過spinInnerClass方法實(shí)現(xiàn)。

  7. spinInnerClass方法
    spinInnerClass方法的主要任務(wù)是動(dòng)態(tài)生成一個(gè)類,這個(gè)類實(shí)現(xiàn)了指定的函數(shù)式接口,并包含了Lambda表達(dá)式的代碼。這個(gè)方法通過直接操作字節(jié)碼來創(chuàng)建類,通常使用ASM庫(kù)來完成。

  8. 使用Unsafe生成匿名類
    spinInnerClass方法可能會(huì)通過Unsafe類的功能來加載生成的字節(jié)碼。Unsafe是JDK內(nèi)部的一個(gè)類,提供了一些底層操作,比如直接內(nèi)存訪問、線程調(diào)度等。其中,Unsafe.defineAnonymousClass方法可以用來加載一個(gè)類的字節(jié)碼,并返回這個(gè)類的Class對(duì)象。這個(gè)方法允許動(dòng)態(tài)生成的類沒有對(duì)應(yīng)的.class文件。

  9. 生成匿名類的過程

    1. 生成字節(jié)碼

      • spinInnerClass方法使用ASM庫(kù)生成實(shí)現(xiàn)了函數(shù)式接口的類的字節(jié)碼。這個(gè)類包含了Lambda表達(dá)式的實(shí)現(xiàn)代碼。
    2. 加載類

      • 使用Unsafe.defineAnonymousClass方法加載生成的字節(jié)碼。這個(gè)方法接受三個(gè)參數(shù):父類的Class對(duì)象、字節(jié)碼數(shù)組、以及與類相關(guān)的常量池補(bǔ)丁。這個(gè)方法返回新加載的類的Class對(duì)象。
    3. 實(shí)例化

      • 通過反射或其他機(jī)制,使用返回的Class對(duì)象創(chuàng)建實(shí)例。這個(gè)實(shí)例實(shí)現(xiàn)了指定的函數(shù)式接口,并包含了Lambda表達(dá)式的代碼。
  10. 綁定到CallSite

    • 創(chuàng)建一個(gè)MethodHandle,指向新生成的類的實(shí)例方法。這個(gè)MethodHandle隨后被綁定到CallSite對(duì)象上,用于后續(xù)的方法調(diào)用。

注意

  • Unsafe類的使用通常不推薦,因?yàn)樗峁┝撕芏鄰?qiáng)大但危險(xiǎn)的底層操作。在JDK 9及以后版本中,Unsafe類的一些功能被限制或替換,以促進(jìn)更安全的編程實(shí)踐。
  • JDK的具體實(shí)現(xiàn)細(xì)節(jié)可能會(huì)隨著版本變化。上述過程主要描述了一種通過Unsafe加載動(dòng)態(tài)生成類的方法,但實(shí)際的實(shí)現(xiàn)可能會(huì)有所不同。
  1. Lambda表達(dá)式執(zhí)行
  • 當(dāng)調(diào)用Lambda表達(dá)式時(shí),通過CallSite間接調(diào)用動(dòng)態(tài)生成的類中的方法。
http://www.risenshineclean.com/news/52932.html

相關(guān)文章:

  • 自己做免費(fèi)手機(jī)網(wǎng)站成都網(wǎng)站快速優(yōu)化排名
  • 網(wǎng)站關(guān)聯(lián)詞搜索怎么做bt磁力搜索引擎在線
  • 做營(yíng)銷型網(wǎng)站的教程打開百度搜索網(wǎng)站
  • 商務(wù)網(wǎng)站建設(shè)需要多少錢廈門seo關(guān)鍵詞優(yōu)化代運(yùn)營(yíng)
  • 公司網(wǎng)站怎么推廣在線域名解析ip地址
  • 網(wǎng)站建設(shè)排名公司哪家好網(wǎng)絡(luò)廣告公司排名
  • 織夢(mèng)html5網(wǎng)站模板百度推廣廣告公司
  • 上海網(wǎng)站建設(shè)公司費(fèi)用百度快速提交入口
  • 網(wǎng)站模板框架seo網(wǎng)站優(yōu)化培訓(xùn)要多少錢
  • 住房建設(shè)廳官方網(wǎng)站成人短期技能培訓(xùn)
  • 梁山專業(yè)網(wǎng)站建設(shè)網(wǎng)址檢測(cè)
  • 做網(wǎng)站開源框架簡(jiǎn)述網(wǎng)絡(luò)推廣的方法
  • 網(wǎng)站域名更換是怎么做的網(wǎng)站是怎么做出來的
  • 可信網(wǎng)站值得做嗎seo推廣專員工作內(nèi)容
  • 河源今日新聞?lì)^條火災(zāi)優(yōu)化設(shè)計(jì)四年級(jí)上冊(cè)語文答案
  • 重慶涪陵網(wǎng)站建設(shè)南寧百度推廣seo
  • 網(wǎng)站推廣方案的構(gòu)成整站優(yōu)化服務(wù)
  • 模板網(wǎng)站音響案例數(shù)字營(yíng)銷包括哪六種方式
  • 網(wǎng)站內(nèi)容管理系統(tǒng)建站企業(yè)網(wǎng)站
  • 內(nèi)蒙古網(wǎng)站建設(shè)價(jià)格輿情網(wǎng)站入口
  • 做視頻網(wǎng)站需要多大帶寬微網(wǎng)站建站平臺(tái)
  • 網(wǎng)站建設(shè)維護(hù)協(xié)議書北海百度seo
  • 品牌網(wǎng)站建設(shè)精湛磐石網(wǎng)絡(luò)百度登錄賬號(hào)首頁(yè)
  • 合作建站方案關(guān)鍵詞優(yōu)化和seo
  • 優(yōu)化是企業(yè)通過網(wǎng)站來做嗎怎么制作小程序
  • 幫忙做網(wǎng)站花西子網(wǎng)絡(luò)營(yíng)銷案例分析
  • 怎么找做網(wǎng)站的人視頻號(hào)最新動(dòng)作
  • 怎么做代理人金沙網(wǎng)站seo的內(nèi)容有哪些
  • 想象力做網(wǎng)站百度官方推廣平臺(tái)
  • 房地產(chǎn) 網(wǎng)站模板南寧百度seo優(yōu)化