2017-08-31 33 views
1

我想在java中實現複製構造函數。我正面臨類的非原始類型字段的問題。在創建新副本時,它正在共享成員。例在java中複製構造函數而不是克隆

public class Bad implements Cloneable { 
    private ArrayList<Integer> a; 
    private Object c; 

    public static void main(String[] args) { 
     Bad b1 = new Bad(); 
     b1.a.add(10); 

     System.out.println(b1.a); 
     Bad b2 = b1.clone(); 
     b2.a.add(12); 

     System.out.println(b1.a); 
    } 

    Bad() { 
     a = new ArrayList<>(); 
     c = null; 
    } 

    Bad(Bad b) { 
     a = b.a; 
     c = b.c; 
    } 

    public Bad clone() { 
     return new Bad(this); 
    } 
} 

,其結果是:

[10] 
[10, 12] 

我不希望這種事情發生。以此爲例。我原來的問題包含更多用戶定義的字段。
或者是否有任何圖書館爲我工作?提前致謝。

+0

嘗試'a = new ArrayList <>(b.a);'這應該使用b中的內容創建一個新的arrayList。一個' – Lino

回答

2

Integer是不可改變的,但你需要創建一個全新的的ArrayList,我的意思是在這裏:

Bad(Bad b) { 
    a = b.a; 
    c = b.c; 
} 

做,而不是

Bad(Bad b) { 
    a = new ArrayList<>(b.a); 
    c = // this here must be copy constructed too 
} 

,然後你會得到

[10]

[10]

+1

實際參數有'整數'類型,而該字段仍然是一個'對象'。你必須找到一個應對機制,以及爲名單 – Andrew

+0

好!謝謝! –

1

正確的方法是創建列表的新實例,而不是將引用傳遞給原始列表。

Bad(Bad b) { 
    a = new ArrayList<>(b.a); 
    c = b.c; // this should call clone or something similar as well 
} 

還要注意的是,如果你將有BA列表內的一些非原始類型,那麼你就必須複製/克隆所有子元素,以及(這是不是現在需要你有整型在它不可變的情況下)。

3

用於複製構造簡單的規則:

  • 原始值可以被複制原樣;它們只是沒有單獨標識的值
  • 對不可變類型引用(例如String,Integer,任何枚舉類常量)也可以原樣複製;雖然原始和複製的對象將共享相同的引用,但引用的對象是不可變的,並且將永遠不會改變
  • 引用可變類型(例如Date,ArrayList,任何數組)必須被複制到一個新的實例類型;否則原件和複製的對象將共享相同的可變領域對象的引用(這是不是你想要的)

製作只包含有原始的和不可改變的值的字段對象的副本是很容易的模式。

複製一個其字段包含可變對象的對象可能會導致該過程艱鉅且昂貴,這取決於可變對象的複雜程度(想象一個包含其值也是地圖的Map的ArrayList)。但是,如果您希望獲得安全副本,則製作可變字段的新副本至關重要。