Lambda and Anonymous Classes

  • Lambda 簡寫的依據

    能夠使用 Lambda 的依據是必須有相應的函數接口(函數接口,是指內部只有一個抽象方法的接口),也就是說你並不能在代碼的任何地方任性的寫Lambda表達式。Lambda表達式另一個依據是類型推斷機制(在上下文信息足夠的情況下,編譯器可以推斷出參數表的類型,而不需要顯式指名)

  • Anonymous Classes

    匿名內部類仍然是一個類,只是不需要程序員顯示指定類名,編譯器會自動爲該類取名。因此如果有如下形式的代碼,編譯之後將會產生兩個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文件分別是主類和匿名內部類產生的:

    AnonymousClass.png

    進一步分析主類MainAnonymousClass.class的字節碼,可發現其創建了匿名內部類的對象:

    // 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 表達式的實現

    Lambda 表達式通過 invokedynamic 指令實現,書寫 Lambda 表達式不會產生新的類。

    public class MainLambda {
    	public static void main(String[] args) {
    		new Thread(
    				() -> System.out.println("Lambda Thread run()")
    			).start();;
    	}
    }
    

    編譯之後:

Lambda

通過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指令進行調用。

https://juejin.im/post/5c3a10c451882524830b0612

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章