2016-11-12 47 views
-2

effective java中聲明的項目:在需要時製作防禦副本,不使用克隆方法制作一個參數的防禦副本,其類型可由不受信任的子副本派對在創建防禦副本時創建新對象而不是克隆

我無法理解這實際上是什麼意思。

+0

如果第三方爲你的班級分類,你不知道'clone()'可能會做什麼。對於大多數項目來說,這會擔心某些不太可能成爲問題的事情,但是對於JDK來說,這是他們必須關注的事情。 –

回答

2

下面是該書在該部分中突出顯示的關注。

public MyOtherClass implements Cloneable { 
    public Object clone() { 
     super.clone(); 
    } 
} 

public MyOtherClass { 
    private MyClass m; 

    public MyOtherClass(MyClass m) { 
     this.m = m.clone(); // Defensive copy. 
    } 
} 

public SneakyClass extends MyClass { 
    public clone() { 
     return this;   // !!!!!! 
    } 
} 

通過傳遞SneakyClass實例到MyOtherClass構造,有人能打敗防守副本的構造函數試圖做的。如您所見,覆蓋clone()不會返回目標對象的副本。

(在這種情況下的解決方案,如果申報MyClass作爲final或聲明MyClass.clone()final。)

1

你所談論的是介紹如何正確地實現一個不可變類的項目。

全款說:

還請注意,我們沒有使用日期的克隆方法,使防守副本。因爲Date是非終結的,所以克隆方法不保證返回一個類爲java.util.Date的對象;它可能會返回專門爲惡意惡作劇設計的不可信子類的實例。例如,這樣的子類可以在其創建時記錄對私有靜態列表中每個實例的引用,並允許攻擊者訪問該列表。這會讓攻擊者自由掌控所有實例。爲了防止這種攻擊,不使用克隆方法來製作其類型可由不受信任方進行分類的參數的防禦副本。

要顯示什麼款的其餘部分被描述,想象一個clone方法做:

public class Foo implements Cloneable { 
    private int bar; 
    private static List<Foo> secretList = new ArrayList<>(); 

    public Foo(int bar) { this.bar = bar; } 

    @Override 
    public Foo clone() { 
     Foo copy = new Foo(this.bar); 
     secretList.add(copy); // this is the line of concern 
     return copy; 
    } 
} 

現在Foo類仍然可以訪問它創建的實例,這意味着它可以惡意修改該實例即使它是不可變類的成員。

+0

長話短說*克隆對象總是根據原始對象的變化進行修改,這是一個壞主意* – emotionlessbananas