Copia superficiale di una mappa in Java


107

A quanto ho capito, ci sono un paio di modi (forse anche altri) per creare una copia superficiale di a Mapin 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();

Si preferisce un modo rispetto all'altro e, in caso affermativo, perché?

Una cosa degna di nota è che il secondo modo fornisce un avviso "Cast non controllato". Quindi devi aggiungere @SuppressWarnings("unchecked")per aggirare il problema, il che è un po 'irritante (vedi sotto).

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

Nelle versioni più recenti di Java (a partire da Java 10, per l'esattezza) è possibile utilizzare il metodo di fabbrica statico Map.copyOf . Ma nota che restituisce una mappa non modificabile!
Oleksandr Pyrohov

Risposte:


106

È sempre meglio copiare utilizzando un costruttore di copie. clone()in Java è danneggiato (vedi SO: come sovrascrivere correttamente il metodo di clonazione? ).

Josh Bloch su Design - Copy Constructor vs Cloning

Se hai letto l'articolo sulla clonazione nel mio libro, soprattutto se leggi tra le righe, saprai che secondo me cloneè profondamente rotto. [...] È un peccato che Cloneablesia rotto, ma succede.

Bloch (che tra l'altro, ha progettato e implementato il framework Collection) è andato anche oltre dicendo che fornisce il clone()metodo solo "perché le persone se lo aspettano". In realtà NON consiglia affatto di usarlo.


Penso che il dibattito più interessante sia se un costruttore di copie sia migliore di una fabbrica di copie, ma questa è una discussione completamente diversa.


1
Sì, questa è una delle mie parti preferite del libro.
lubrificanti poligenici

1
Non mi piace dire che clone () è rotto. Preferisco dire che il clone è stata una pessima decisione di progettazione e può danneggiarti molto se non lo usi correttamente. Inoltre, potresti non fidarti mai dei metodi clone () di altre persone. Quindi finiamo simili, cerchiamo di evitarlo, ma non è rotto.
santiagobasulto

4
L'utilizzo del copy ctor non richiede di sapere quale implementazione di Map stai copiando? Sembra una limitazione inutile.
jon-hanson

"che fornisce solo il metodo clone () solo" perché la gente se lo aspetta "" - fonte?
Adam Parkin

60

Nessuno dei due: il costruttore a cui ti riferisci è definito per l' implementazione HashMap di una mappa , (così come per gli altri) ma non per l'interfaccia Map stessa (ad esempio, considera l' implementazione del Provider dell'interfaccia Map: tu non troverà quel costruttore).

D'altra parte non è consigliabile utilizzare il clone()metodo, come spiegato da Josh Bloch.

Rispetto all'interfaccia Map (e alla tua domanda, in cui chiedi come copiare una mappa, non una HashMap), dovresti usare Map # putAll () :

Copia tutte le mappature dalla mappa specificata a questa mappa (operazione facoltativa). L'effetto di questa chiamata è equivalente a quello di chiamare put (k, v) su questa mappa una volta per ogni mappatura dalla chiave k al valore v nella mappa specificata.

Esempio:

// 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
Quindi, per chiarire: se sai che stai copiando su un'implementazione di Mapcui ha un costruttore di copia, non c'è motivo di non usare il costruttore di copia allora?
Adam Parkin

2
Esattamente, e si può anche pensare che il contrario: se si utilizza putAllsi non è necessario sapere se l' Mapapplicazione in uso dispone di un costruttore di copia oppure no. Un semplice costruttore di copia di qualsiasi Mapimplementazione è quindi ridondante.
Luca Fagioli

1
Certo, anche se generalmente mi piacciono le 1 battute meglio delle 2 battute. ;)
Adam Parkin

11

Copia una mappa senza conoscerne l'implementazione:

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

3
Considerare l'aggiunta di <K,V>parametri di tipo per garantire l'indipendenza dai tipi.
Barett

1
E le mappe senza costruttori senza argomenti?
Isaac Saffold
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.