java中Lambda表示式的實現原理
阿新 • • 發佈:2021-10-26
簡單使用
import java.util.function.Consumer;
public class TestLambda {
public static void main(String[] args) {
Consumer<String> consumer = System.out::println;
consumer.accept("hello");
}
}
反編譯後位元組碼
getstatic #2 <java/lang/System.out> dup invokestatic #3 <java/util/Objects.requireNonNull> pop invokedynamic #4 <accept, BootstrapMethods #0> astore_1 aload_1 ldc #5 <hello> invokeinterface #6 <java/util/function/Consumer.accept> count 2 return
invokedynamic是Java 7為了實現在JVM上執行動態語言而引入的一條新的虛擬機器指令,它可以實現在執行期動態解析出呼叫點限定符所引用的方法,
然後再執行該方法,invokedynamic指令的分派邏輯是由使用者設定的引導方法決定。Lambda表示式的核心就是invokedynamic指令。
實現原理
通過debug可知,Lambda表示式最終是通過InnerClassLambdaMetafactory類來建立匿名內部類來實現的,使用ASM來建立匿名內部類
最後通過Unsafe(java提供的魔法類,可以操作底層資源)的defineAnonymousClass()方法來將位元組陣列轉換成Class物件,
類似於ClassLoader的loadClass()方法的功能,但這種方法生成的匿名類不顯式掛在任何ClassLoader下面,只要當該類沒有存在的例項物件、
且沒有強引用來引用該類的Class物件時,該類就會被GC回收。因此這種匿名內部類相比於Java語言層面的匿名內部類更容易回收。
通過匿名內部類的Class物件建立呼叫點CallSite
總結
在Lambda表示式實現中,通過invokedynamic指令呼叫引導方法生成呼叫點,在此過程中,會通過ASM動態生成位元組碼,
而後利用Unsafe的defineAnonymousClass方法定義實現相應的函式式介面的匿名類,然後再例項化此匿名類,
並返回與此匿名類中函式式方法的方法控制代碼關聯的呼叫點;而後可以通過此呼叫點實現呼叫相應Lambda表示式定義邏輯的功能。