2016-04-13 7 views
1

Mein Professor sagte, sie seien völlig verschieden, aber ich lese, dass sie sich ziemlich ähnlich sind. Ich weiß nicht, welchen Kontext "anders" er meinte. Und wenn diese Frage bereits beantwortet wurde, verlinke sie einfach. Vielen Dank.Kann jemand den Unterschied zwischen einer tiefen Kopie und einer defensiven Kopie erklären?

+0

Nur der Zweck. Eine tiefe Kopie bedeutet, dass Sie jedes Element kopieren (ohne Angabe des Grundes), und eine defensive Kopie bedeutet, dass Sie kopieren, um zu verhindern, dass jemand anders auf dasselbe Objekt zugreift (z. B. zur Thread-Sicherheit). – markspace

+0

Ich kann in einem Toyota zur Arbeit fahren, aber zur Arbeit fahren ist völlig anders als ein Toyota. Einer ist eine Art von Auto, einer ist eine Art, wie ein Auto benutzt wird. Eine tiefe Kopie ist eine Art von Kopie und eine defensive Kopie ist eine Art, wie eine Kopie verwendet wird. – Radiodef

Antwort

1

Tiefe Kopie: eine Art von Objektkopiertechniken: alle Daten in der Struktur tief kopieren. Eine "harte" Methode, um eine tiefe Kopie eines Objekts zu erzeugen, besteht darin, sie zu serialisieren und dann zu entserialisieren. Für Bäume ist rekursives Kopieren im Allgemeinen eine effiziente Lösung.

Defensive Kopie: Ergebnis einer Operation zum Schutz interner Daten. Normalerweise ist es eine tiefe oder flache Kopie, die verwendet wird, um einen unerwünschten Zugriff durch ein internes Referenzergebnis zu verhindern.

From this article:

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

In der Regel sollten Sie defensive Kopie verwenden, um eine innere Anordnung, Sammlung oder eine andere Struktur zu schützen. Wenn wir einfach mit (einem Verweis auf) dem Array zurückkommen, könnte der Benutzer unsere interne Struktur ändern!

Siehe ein Beispiel.

Tom schreibt eine Klasse, die gemächlich einige Aggregationen einer Integer Sammlung Caches:

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; 
    } 

} 

Jerry verwendet die oben Klasse auf diese Weise:

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!) 

Ausgang:

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

Was ist das Hauptproblem? Tom verliert eine veränderliche innere Struktur. Was ist die Lösung? In getIntegers() eine Kopie davon vor der Rückkehr machen:

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

In einigen Fällen whould ein unveränderliches Wrapper auch richtig sein:

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

Leistung? Im Allgemeinen, mach dir keine Sorgen darüber. Die schnelle Objekterstellung ist einer der wichtigsten Java-Vorteile. Natürlich gibt es komplexe Strukturen, die ineffizient kopiert werden. In diesem Fall können Sie die Copy-on-Write-Technik verwenden. Einige große Datenstrukturimplementierungen verfügen über eine Unterstützung für Copy-on-Write, z. B. BigList.

+1

Defensive Kopien müssen keine tiefen Kopien sein. Sagen wir, ich habe ein 'Klasse Foo {privates Widget [] Widgets; ...} 'wo' Widget' veränderbar ist und ich eine Methode habe, die meine 'Widgets' zurückgibt. Ich kann das Array flach kopieren, um zu verhindern, dass die Außenwelt die internen Details meines "Foo" verändert, aber ich muss nicht jedes "Widget" kopieren, damit es eine defensive Kopie ist. – Radiodef

+0

Korrekt. Ich habe den Text geändert. –

+0

@Radiodef Ich verstehe nicht, wie eine defensive Kopie eine flache Kopie sein kann? Wenn Sie eine flache Kopie verwenden, kann der Empfänger das Innere des Objekts ändern, das keine defensive Kopie ist. – Nier

Verwandte Themen