亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

方法引用似乎并不總是捕獲實例

方法引用似乎并不總是捕獲實例

蝴蝶不菲 2023-01-05 17:25:37
我知道關于這個主題有很多問題,即使是最近的一個問題,但我仍然無法解決一件事??紤]以下功能接口:@FunctionalInterfaceinterface PersonInterface {    String getName();}而這個實現:class Person implements PersonInterface {    private String name;    public Person(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}如果我查看這些線程1和2,我希望輸出以下代碼"Bob"而不是拋出 aNullPointerException因為據我所知,當我創建供應商時,它會捕獲Person實例。Person p = new Person("Bob");Supplier<String> f = p::getName;p = null;System.out.println(f.get());它正確輸出"Bob"現在我不明白的是為什么下面的代碼也沒有輸出"Bob"?Person p = new Person("Bob");Supplier<String> f = p::getName;p.setName("Alice");System.out.println(f.get());它實際上輸出"Alice"在我看來,在第一個示例中,lambda 在創建時捕獲了 Person 對象的狀態,并且在調用它時不會嘗試重新評估它,而在第二種情況下,它似乎沒有捕獲它,但在調用時重新評估它。編輯 在重新閱讀其他線程和 Eran 的回答后,我用 2 個人指向同一個實例寫了那個:Person p1 = new Person("Bob");Person p2 = p1;Supplier<String> f1 = p1::getName;Supplier<String> f2 = p2::getName;p1 = null;p2.setName("Alice");System.out.println(f1.get());System.out.println(f2.get());現在我可以看到它們都輸出"Alice",即使 p1 為空,因此方法引用捕獲了實例本身,而不是我錯誤假設的狀態。
查看完整描述

2 回答

?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

在我看來,在第一個示例中,lambda 在創建時捕獲了 Person 對象的狀態,并且在調用它時不會嘗試重新評估它,而在第二種情況下,它似乎沒有捕獲它,但在調用時重新評估它。

首先,它是一個方法引用,而不是 lambda 表達式。

在這兩種情況下,對Person實例的引用都被方法引用捕獲(這不是“Person 對象的狀態”)。這意味著如果Person實例的狀態發生變化,則執行功能接口的方法的結果可能會發生變化。

方法引用不會創建Person它捕獲其引用的實例的副本。


查看完整回答
反對 回復 2023-01-05
?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

這在某種程度上與 lambdas 或方法引用無關,它只是您正在使用的這些構造的副作用。


為了更簡單的推理,您可以將其視為:


static class SupplierHolder {

    private final Person p;

    // constructor/getter

}


static class Person {

    private String name;

    // constructor/getter/setter

}

當您創建:Supplier<String> f = p::getName;時,您可以將其視為創建一個SupplierHolder以 aPerson作為輸入并具有對其getName.


這就像做:


Person p = new Person("Bob");

SupplierHolder sh = new SupplierHolder(p);

p = null; // this has no effect on the reference that SupplierHolder holds

System.out.println(sh.getPerson().getName()); 

在你的第二個例子中,你有:


Person p = new Person("Bob");

SupplierHolder sh = new SupplierHolder(p); 

p.setName("Alice");

現在p引用和SupplierHolder持有的引用“作用于”同一個實例——它們指向同一個對象。


這在現實中并不完全相同,但我想證明了這一點。


查看完整回答
反對 回復 2023-01-05
  • 2 回答
  • 0 關注
  • 163 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號