2014-05-11 58 views
2

在Java 8中,它看起來像一個類的lambdas保存在一個數組中。例如,讓我們說我們有這個類:獲取類的列表lambdas

public class LambdaFactory { 
    public Supplier<Integer> getOne(){ 
     return() -> 42; 
    } 

    public Supplier<Integer> getTwo(){ 
     return() -> 128; 
    } 

    public Supplier<Integer> getThree(){ 
     return() -> 3; 
    } 
} 

,然後我把它打印出來,像這樣:

System.out.println(factory.getOne()); 
    System.out.println(factory.getOne()); 
    System.out.println(factory.getTwo()); 
    System.out.println(factory.getThree()); 

輸出會像

[email protected] 
[email protected] 
[email protected] 
[email protected] 

所以我們可以看到這裏有兩件事。被稱爲兩次的相同lambda給了我們相同的lambda對象(這與每次我們可以獲得新內部類的anon內部類不一樣)。我們也看到他們看起來像是被保存在某種類型的「Lambda」結構中,這是類的一部分

我的問題是,我可以在課堂上看到lambda表達式嗎?我沒有任何理由這樣做,我只是喜歡解剖東西

+0

是什麼讓你覺得他們在一個數組? – assylias

+3

我認爲你在這裏得出錯誤的結論。匿名內部類通常將'$ 1'構造作爲其名稱的一部分 - 這是一個常見的習慣用法,即帶有美元符號的類名是在運行時構建的,例如使用動態Proxy類時。 –

+0

我想我不知道它是一個數組還是它是什麼,但lambda表達式是一樣的。如果我對getOne的兩個供應商執行jUnit Assert.assertSame,它將通過,但如果它是annon內部類,則會失敗。請參閱https://github.com/ryber/J8Lambda/blob/master/src/test/java/examples/ObjectLifeCycle.java – ryber

回答

10

lambda是由JRE創建的,它們的創建方式是由JRE控制的,並且可能會因不同的JRE供應商而有所不同,並可能在未來發生變化版本。

如果你想有樂趣,你可以在運行時創建一個lambda它具有類文件中沒有相應的信息:

import java.lang.invoke.*; 

public class ManualLambda { 
    public static void main(String[] args) throws Throwable { 
    MethodHandles.Lookup me=MethodHandles.lookup(); 
    MethodType t=MethodType.methodType(void.class); 
    MethodType rt=MethodType.methodType(Runnable.class); 
    CallSite site = LambdaMetafactory.metafactory(
     me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t); 
    MethodHandle factory=site.getTarget(); 
    Runnable r=(Runnable)factory.invoke(); 

    System.out.println("created lambda: "+r); 
    r.run(); 
    } 
    private static void sayHello() { 
     System.out.println("hello world"); 
    } 
} 

上面的代碼回溯創建拉姆達時會發生什麼。但是對於編譯時(「真實」)lambda表達式,整個事件由單個的invokedynamic字節碼指令觸發。 LambdaMetafactory.metafactory(…)方法是引導程序第一次執行invokedynamic指令時調用的方法。返回的CallSite對象與invokedynamic指令永久關聯。如果CallSiteConstantCallSite及其MethodHandle在每次執行時都返回相同的lambda對象,則invokedynamic指令將永遠「產生」相同的lambda實例。

2

The Java Language Specification states

在運行時,一個lambda表達式的評估是類似於類實例創建表達的 評價,只要正常 完成產生對一個對象的引用。 [...]

具有以下屬性的類的新實例是 已分配和初始化,或者引用了具有以下屬性的 屬性的現有實例。

[...]

這些規則是爲了提供靈活性, Java編程語言的實現,在於:

  • 一個新的對象不一定在每一個評估來分配。
  • [...]

因此,它是由編譯器或運行時環境來決定,當一個lambda表達式求什麼應該被退回。

我的問題是,我可以在課堂上看到lambdas嗎?我不 有任何理由這樣做,我只是喜歡解剖事情

可以認爲一個lambda表達式作爲任何其它類常量的,一個String,一個整數文字,等等,這些都是常量出現在.class文件的常量池中。這些是對運行時創建和存在的對象的引用。無法從類的常量池中引用實際對象。

在lambda的情況下,它無論如何不會有幫助,因爲它實際上可能不是同一個對象。