2010-03-01 12 views
93

Wie ich es verstehe, gibt es ein paar Möglichkeiten, (vielleicht auch andere) eine flache Kopie eines Map in Java zu erstellen:Shallow Kopie einer Karte in Java

Map<String, Object> data = new HashMap<String, Object>(); 
Map<String, Object> shallowCopy; 

// first way 
shallowCopy = new HashMap<String, Object>(data); 

// second way 
shallowCopy = (Map<String, Object>) ((HashMap<String, Object>) data).clone(); 

ist ein Weg, über bevorzugte der andere, und wenn ja, warum?

Eine erwähnenswerte Sache ist, dass die zweite Möglichkeit eine "ungeprüfte Cast" Warnung gibt. Sie müssen also @SuppressWarnings("unchecked") hinzufügen, um es zu umgehen, was ein wenig irritierend ist (siehe unten).

@SuppressWarnings("unchecked") 
public Map<String, Object> getDataAsMap() { 
    // return a shallow copy of the data map 
    return (Map<String, Object>) ((HashMap<String, Object>) data).clone(); 
} 

Antwort

98

Es ist immer besser, mit einem Kopierkonstruktor zu kopieren. clone() in Java ist kaputt (siehe SO: How to properly override clone method?).

Josh Bloch on Design - Copy Constructor versus Cloning

Wenn Sie den Artikel über das Klonen in meinem Buch gelesen haben, vor allem, wenn man zwischen den Zeilen lesen, werden Sie wissen, dass ich denke, clone tief gebrochen ist. [...] Es ist eine Schande, dass Cloneable kaputt ist, aber es passiert.

Bloch (der übrigens, entworfen und die Sammlung Framework implementiert) ging sogar noch weiter zu sagen, dass er nur die clone() Methode liefert nur „weil die Leute es erwarten“. Er empfiehlt tatsächlich nicht, es überhaupt zu benutzen.


Ich denke, die mehr interessante Debatte ist, ob eine Kopie Konstruktor ist besser als eine Kopie der Fabrik, aber das ist eine andere Diskussion zusammen.

+2

Nizza Antwort, danke. – dcp

+0

Ja, das ist einer meiner Lieblingsteile des Buches. – polygenelubricants

+1

Ich möchte nicht sagen, dass clone() defekt ist. Ich ziehe es vor zu sagen, dass der Klon eine schreckliche Designentscheidung war und Ihnen viel Schaden zufügen kann, wenn Sie ihn nicht richtig benutzen.Außerdem könnten Sie anderen Personen niemals klone() - Methoden trauen. Also enden wir ähnlich, versuchen es zu vermeiden, aber es ist nicht kaputt. – santiagobasulto

49

Keiner der beiden: die constructor, die Sie sich beziehen, für die HashMap Implementierung eines Map definiert ist, (wie auch für andere), aber nicht für die Karte Schnittstelle selbst (zum Beispiel betrachten wir die Provider Umsetzung der Kartenschnittstelle: Sie werden diesen Konstruktor nicht finden).

Auf der anderen Seite ist es nicht ratsam, die clone() Methode zu verwenden, wie von Josh Bloch erklärt.

In Bezug auf der Map-Schnittstelle (und Ihre Frage, in der Sie fragt, wie eine Karte kopieren, kein HashMap), sollten Sie verwenden Map#putAll():

Kopieren alle der Abbildungen aus dem angegebenen Karte zu dieser Karte (optionale Operation). Die Wirkung dieses Aufrufs entspricht der von , die put (k, v) auf dieser Karte einmal für jede Zuordnung von Schlüssel k zu Wert v in der angegebenen Zuordnung aufruft.

Beispiel:

// HashMap here, but it works for every implementation of the Map interface 
Map<String, Object> data = new HashMap<String, Object>(); 
Map<String, Object> shallowCopy = new HashMap<String, Object>(); 

shallowCopy.putAll(data); 
+2

Also, um zu verdeutlichen: Wenn du * weißt * kopiere * zu * einer Implementierung von 'Map', die einen Kopierkonstruktor hat, gibt es keinen Grund, den Kopierkonstruktor dann nicht zu benutzen? –

+2

Genau, und Sie können es sogar andersherum denken: Wenn Sie 'putAll' verwenden, müssen Sie _keine Ahnung_ haben, wenn die von Ihnen verwendete' Map'-Implementierung einen Kopierkonstruktor hat oder nicht. Ein bloßer Kopierkonstruktor einer beliebigen "Map" -Implementierung ist somit redundant. –

+1

Sicher, obwohl ich generell 1-Liner besser als 2-Liner mag. ;) –

7

Kopieren Sie eine Karte, ohne ihre Implementierung zu wissen:

static final Map shallowCopy(final Map source) throws Exception { 
    final Map newMap = source.getClass().newInstance(); 
    newMap.putAll(source); 
    return newMap; 
} 
+2

Erwägen Sie, '' Typparameter hinzuzufügen, um Typsicherheit zu gewährleisten. – Barett

+0

Was ist mit Karten ohne Konstruktoren mit null Argumenten? –