1. 程式人生 > 其它 >java中Lambda表示式的實現原理

java中Lambda表示式的實現原理

簡單使用

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表示式定義邏輯的功能。

參考

Java魔法類:Unsafe應用解析