2012-08-17 57 views
3

我有一個關於創建Immutable類的查詢。以下是我走在考慮幾點:關於不可變類防禦性複製

  1. 使該類最終
  2. 讓所有成員最終,將它們明確,在靜態塊,或在構造
  3. 讓私人
  4. 所有成員
  5. No修改狀態的方法
  6. 要非常小心地限制對可變成員組件的訪問(請記住該字段可能是最終的,但對象仍然可以是可變的,即private final Date imStillMutable) - 請參閱防禦性複製或其表兄複製構造函數更多信息。


但我不完全理解的5點全部,你可以請指教或告訴我一個例子,其中的5點在這個例子清楚了嗎?

回答

5

第5點建議,任何時候你有任何方法將返回某事做一個可變的對象,你會想創建一個獨立於私人狀態的副本。例如:

public final class Foo 
{ 
    private final List<String> strings; 

    public Foo(List<String> strings) 
    { 
     // Defensive copy on construction. Protects from constructing 
     // code mutating the list. 
     this.strings = new ArrayList<String>(strings); 
    } 

    public List<String> getStrings() 
    { 
     // Defensive copy on read. Protects from clients mutating the list. 
     return new ArrayList<String>(strings); 
    } 
} 

請注意,防禦性複製僅在狀態可變時才需要。例如,如果您使用ImmutableList(例如來自Guava)作爲上述課程中的州,則需要創建一個新的施工列表(除非輸入也是ImmutableList),但而不是getStrings

另請注意,在這種情況下String是不可變的,所以我們不需要複製每個字符串。如果這是一個List<StringBuilder>,我們需要創建一個新列表,並將每個元素的新副本作爲防禦副本的一部分。正如你所看到的,當你所有的狀態都不可變時,生活變得更簡單。

+0

我在尋找這個主題,並偶然發現了這個答案。 List 其中X對象不受我們控制並且可變且不提供可靠的克隆方法的情況下該怎麼辦? – RandomQuestion 2013-08-28 06:07:03

+1

@Jitendra:這取決於上下文。 *也許*您處於可以信任其他代碼而不改變值的情況下......或者您需要自己有效地克隆這些值。這裏沒有單一的正確答案。 – 2013-08-28 08:16:44

3

final意味着指針不能指向另一個引用。 例如:

final Object obj = new Object(); 
obj = new Object(); //Invalid 

final並不妨礙modifiying對象:

obj.setWhatever("aaa"); //Perfectly valid 

如果您還沒有限制訪問的成員,那麼任何人都可以獲取對象並對其進行修改。

例如:yourClass.getObject().setWhatever("aaa").

防守複製意味着getObject()不會直接返回對象,但它會使它的一個副本,然後返回。這樣,如果調用方修改返回的對象,它將不會修改該類的原始成員。