Lambda 簡寫的依據java
可以使用 Lambda 的依據是必須有相應的函數接口(函數接口,是指內部只有一個抽象方法的接口),也就是說你並不能在代碼的任何地方任性的寫Lambda表達式。Lambda表達式另外一個依據是類型推斷機制(在上下文信息足夠的狀況下,編譯器能夠推斷出參數表的類型,而不須要顯式指名)程序員
Anonymous Classeside
匿名內部類仍然是一個類,只是不須要程序員顯示指定類名,編譯器會自動爲該類取名。所以若是有以下形式的代碼,編譯以後將會產生兩個class文件:函數
public class MainAnonymousClass {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("Anonymous Class Thread run()");
}
}).start();;
}
}
複製代碼
編譯以後文件分佈以下,兩個class文件分別是主類和匿名內部類產生的:spa
進一步分析主類MainAnonymousClass.class的字節碼,可發現其建立了匿名內部類的對象:code
// javap -c MainAnonymousClass.class
public class MainAnonymousClass {
...
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Thread
3: dup
4: new #3 // class MainAnonymousClass$1 /*建立內部類對象*/
7: dup
8: invokespecial #4 // Method MainAnonymousClass$1."<init>":()V
11: invokespecial #5 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
14: invokevirtual #6 // Method java/lang/Thread.start:()V
17: return
}
複製代碼
Lambda 表達式的實現cdn
Lambda 表達式經過 invokedynamic 指令實現,書寫 Lambda 表達式不會產生新的類。對象
public class MainLambda {
public static void main(String[] args) {
new Thread(
() -> System.out.println("Lambda Thread run()")
).start();;
}
}
複製代碼
編譯以後:blog
經過javap反編譯命名,咱們更能看出Lambda表達式內部表示的不一樣:接口
// javap -c -p MainLambda.class
public class MainLambda {
...
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; /*使用invokedynamic指令調用*/
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: invokevirtual #5 // Method java/lang/Thread.start:()V
15: return
private static void lambda$main$0(); /*Lambda表達式被封裝成主類的私有方法*/
Code:
0: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #7 // String Lambda Thread run()
5: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
複製代碼
反編譯以後咱們發現Lambda表達式被封裝成了主類的一個私有方法,並經過invokedynamic指令進行調用。