2015-02-02 13 views
15

Ho bisogno di fare una copia di HashMap<Integer, List<MySpecialClass> > ma quando cambio qualcosa nella copia voglio che l'originale rimanga lo stesso. quando rimuovo qualcosa dallo List<MySpecialClass> dalla copia rimane nello List<MySpecialClass> nell'originale.Come copiare HashMap (copia non superficiale) in Java

Se ho ben capito, questi due metodi creano solo copia superficiale, che non è quello che voglio:

mapCopy = new HashMap<>(originalMap); 
mapCopy = (HashMap) originalMap.clone(); 

ho ragione?

Esiste un modo migliore per farlo rispetto alla semplice iterazione di tutti i tasti e di tutti gli elementi dell'elenco e della copia manuale?

risposta

11

Hai ragione che una copia superficiale non soddisferà le tue esigenze. Avrà copie dei List s dalla mappa originale, ma quei List s farà riferimento agli stessi List oggetti, in modo che apparirà una modifica ad un List da un HashMap nel corrispondente List dall'altro HashMap.

Non c'è una copia profonda in dotazione per un HashMap in Java, quindi si avrà ancora per scorrere tutte le voci e le put nella nuova HashMap. Ma dovresti anche fare una copia di List ogni volta. Qualcosa di simile a questo:

public static HashMap<Integer, List<MySpecialClass>> copy(
    HashMap<Integer, List<MySpecialClass>> original) 
{ 
    HashMap<Integer, List<MySpecialClass>> copy = new HashMap<Integer, List<MySpecialClass>>(); 
    for (Map.Entry<Integer, List<MySpecialClass>> entry : original.entrySet()) 
    { 
     copy.put(entry.getKey(), 
      // Or whatever List implementation you'd like here. 
      new ArrayList<MySpecialClass>(entry.getValue())); 
    } 
    return copy; 
} 

Se si desidera modificare le singole MySpecialClass oggetti, e hanno le modifiche non si riflettono nei List s del vostro copiato HashMap, quindi si bisogno di fare nuove copie di loro troppo.

+0

Nella dichiarazione del ciclo for, non è possibile trovare original.entrySet() anziché copy.entrySet()? – Mathis

+0

@ user3394494 Sì, hai ragione. Immagino sia quello che succede quando digito il codice velocemente. Modificata. – rgettman

1

si stanno facendo una copia del HashMap stesso, in modo da cambiare la copia HashMap non cambierà la HashMap originale (cioè l'aggiunta o la rimozione di voci), ma perché gli oggetti che sono stati memorizzati non sono tipi primitivi, la lista che si recupera con una data chiave sarà uguale se recuperata dalla prima o dalla seconda mappa.

Quindi, c'è ancora UNA sola copia di tale elenco, referenziata da entrambe le mappe: la modifica della Lista cambia non importa quale riferimento si usa per accedervi.

Se si desidera che l'Elenco reale sia una copia separata, si dovrà fare ciò che è stato detto: scorrere il set di voci della HashMap e creare una copia di ogni Lista manualmente, aggiungendola alla nuova mappa mentre si partire.

Se c'è un modo migliore di quello, non so di cosa si tratta.

15

Purtroppo non ha bisogno dell'iterazione. Ma è piuttosto banale con Java 8 flussi:

mapCopy = map.entrySet().stream() 
    .collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue())); 
+0

Non sono così familiare con i flussi. Quando ho provato la tua soluzione, dà un errore: metodo non statico getKey() non può essere referenziato da un contesto statico, lo stesso con getValue(), come modificarlo in modo che funzioni? Grazie – Mathis

+0

Mi dispiace - lo aggiusterò nel codice. – sprinter

+0

Purtroppo al momento non sono a un compilatore quindi non ho avuto la possibilità di testarlo. Prova questo e se non funziona rimuoverò la risposta finché non avrò avuto la possibilità di testarlo. – sprinter

-1

serializzare JSON e deserializzare dopo:

Map<String, Object> originalMap = new HashMap<>(); 
String json = new Gson().toJson(originalMap); 
Map<String, Object> mapCopy = new Gson().fromJson(
    json, new TypeToken<Map<String, Object>>() {}.getType()); 

Per le classi speciali potrebbe essere necessario write a custom deserializer.