2016-04-13 54 views
1

我的教授說他們完全不同,但我讀他們很相似。我不知道他指的是什麼背景「不同」。 如果這個問題已經被回答,只是鏈接它。謝謝。有人可以解釋深層複製和防禦性複製之間的區別嗎?

+0

只是目的。深層複製意味着您複製每個元素(不指定原因),而防禦複製意味着您複製以防止其他人訪問同一對象(例如,爲了線程安全)。 – markspace

+0

我可以開車去豐田工作,但開車上班與豐田完全不一樣。一種是汽車,一種是使用汽車的方式。深層副本是一種副本,防禦副本是使用副本的一種方式。 – Radiodef

回答

1

深層複製:一種對象複製技術:深層複製結構中的所有數據。產生對象的深層副本的「苛刻」方法是序列化然後反序列化它。對於樹木,通常遞歸複製是一種有效的解決方案。

防禦性拷貝:保護內部數據的操作結果。通常它是一個深度或淺度的副本,用於防止通過內部參考結果進行不必要的訪問。

From this article:

public int[] getValues() { 
    return Arrays.copyOf(values, values.length); 
} 

在一般情況下,你應該使用防禦性副本,以保護內部數組,集合或其他結構。如果我們簡單地返回(對數組的引用),用戶可以修改我們的內部結構!

查看示例。

湯姆寫了一個類懶洋洋緩存的Integer收集的一些彙總:

public class CachedIntegerAggregator { 

    private List<Integer> integers; 

    private boolean isSumCalculated = false; 
    private int sum = 0; 

    private boolean isMultiCalculated = false; 
    private int multi = 0; 

    public CachedIntegerAggregator(Integer... integers) { 
     this(Arrays.asList(integers)); 
    } 

    public CachedIntegerAggregator(Collection<Integer> integers) { 
     this.integers = new ArrayList<Integer>(integers); 
    } 

    public List<Integer> getIntegers() { 
     return integers; 
    } 

    public int getSum() { 
     if (!isSumCalculated) { 
      sum = 0; 
      for (Integer integer: integers) { 
       sum += integer; 
      } 
      isSumCalculated = true; 
     } 
     return sum; 
    } 

    public int getMulti() { 
     if (!isMultiCalculated) { 
      multi = 1; 
      for (Integer integer: integers) { 
       multi *= integer; 
      } 
      isMultiCalculated = true; 
     } 
     return multi; 
    } 

} 

傑裏使用上述類以這樣的方式

CachedIntegerAggregator aggregator = new CachedIntegerAggregator(2, 3, 4); 

// hm, what is the sum? 
System.out.println(aggregator.getSum()); 

// let's print of integers 
List<Integer> integers = aggregator.getIntegers(); 
System.out.println(integers); 

// now, see the double 
int size = integers.size(); 
for (int i = 0; i < size; i++) { // (oops! this changes internal data!) 
    integers.set(i, integers.get(i) * 2); 
} 
System.out.println(integers); 

// hm, see sum and multi 
System.out.println(aggregator.getSum()); 
System.out.println(aggregator.getMulti()); // (oops! total inconsistency!) 

輸出:

9 
[2, 3, 4] 
[4, 6, 8] 
9 
192 

主要問題是什麼?湯姆泄漏了一個可變的內部結構。解決辦法是什麼?在getIntegers()做它的一個副本返回之前:

public List<Integer> getIntegers() { 
    return new ArrayList<Integer>(integers); 
} 

在某些情況下,一個不可變的包裝是對子級也沒錯:

public List<Integer> getIntegers() { 
    return Collections.unmodifiableList(integers); 
} 

性能?一般來說,不要擔心。快速創建對象是Java的主要優勢之一。當然,有複雜的結構,將被低效地複製。在這種情況下,您可以使用寫入時複製技術。一些大數據結構實現已經建立在寫入時複製支持上,如BigList

+1

防禦性副本不必是深層副本。假設我有一個'Foo類{private Widget []小部件; ...}'Widget'是可變的,我有一個方法返回我的'widgets'。我可以淺拷貝數組以防止外界修改我的'Foo'的內部細節,但我不必複製每個'Widget',因爲它是一個防禦副本。 – Radiodef

+0

正確。我改變了文字。 –

+0

@Radiodef我不明白如何防禦副本是一個淺拷貝?如果你使用淺拷貝,那麼接收者可以修改不是防禦拷貝的對象的內部。 – Nier

相關問題