Comment copier HashMap (et non shallow copy) en Java

j'ai besoin de faire une copie de HashMap<Integer, List<MySpecialClass> > mais quand je change quelque chose dans la copie je veux que l'original reste le même. j'.e quand j'ai supprimer quelque chose de la List<MySpecialClass> à partir de la copie qu'il reste dans le List<MySpecialClass> dans l'original.

si je le comprends bien, ces deux méthodes ne créent qu'une copie superficielle qui n'est pas ce que je veux:

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

Suis-je le droit?

Est-il une meilleure façon de le faire que de simplement itérer sur toutes les touches et tous les éléments de la liste et copie manuellement?

24
demandé sur Mathis 2015-02-03 02:07:46

5 réponses

vous avez raison qu'une copie superficielle ne répond pas à vos exigences. Il y aura des copies du Lists à partir de votre carte d'origine, mais ceux List S fera référence à la même List objets, de sorte qu'une modification à un List d'un HashMap apparaîtra dans le List de l'autre HashMap.

il n'y a pas de copie profonde fournie pour un HashMap en Java, donc vous devrez toujours boucler toutes les entrées et put dans la HashMap. Mais vous devez également faire une copie du List à chaque fois aussi. Quelque chose comme ceci:

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

Si vous souhaitez modifier votre MySpecialClass les objets, et les changements figurent pas dans le Lists de votre copié HashMap, vous devrez alors faire de nouvelles copies de trop.

16
répondu rgettman 2015-02-02 23:57:52

cela nécessite malheureusement une itération. Mais C'est assez trivial avec Java 8 streams:

mapCopy = map.entrySet().stream()
    .collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue()));
20
répondu sprinter 2015-02-03 00:47:40

vous pouvez essayer le clonage profond. Regardez par exemple https://code.google.com/p/cloning/

2
répondu Nabil Echaouch 2015-02-02 23:17:38

vous faites une copie du HashMap lui-même, donc changer la copie du HashMap ne changera pas le HashMap original (c.-à-d. ajouter ou supprimer des entrées), mais parce que les objets que vous avez stockés ne sont pas des types primitifs, la liste que vous récupérez avec une clé donnée sera la même si récupéré à partir de la première ou de la deuxième carte.

ainsi, il n'y a toujours qu'une seule copie de cette liste, référencée par les deux cartes: changer la liste change peu importe quelle référence vous utilisez pour accéder il.

si vous voulez que la liste actuelle soit une copie séparée, vous devrez faire comme vous l'avez dit: itérer sur le jeu d'entrée de HashMap et créer une copie de chaque liste manuellement, en l'ajoutant à la nouvelle carte au fur et à mesure.

S'il y a un meilleur moyen que cela, je ne sais pas ce que c'est.

1
répondu Brian 2015-02-02 23:15:51

Sérialiser en json et désérialiser par la suite:

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());

pour les classes spéciales vous pourriez avoir besoin de écrire une coutume deserializer.

-2
répondu neu242 2017-09-06 12:07:48