web-dev-qa-db-fra.com

Copier un HashMap dans Java

J'essaie de conserver un conteneur temporaire d'une classe qui contient member:

HashMap<Integer,myObject> myobjectHashMap

Une classe appelée myobjectsList

Alors je fais

myojbectsListA = new myojbectsList();
myojbectsListB = new myobjectsList();

then: Ajouter des éléments de hashmap à A (like2)

ensuite

myobjectListB = myobjectListA; //B has 2

puis: Ajoutez des éléments hashmap à A; (comme 4 de plus)

retournez ensuite A aux éléments stockés dans B;

myobjectListA = myobjectListb;

mais quand je fais cela, B grandit avec A tandis que j'ajoute des éléments hashmap à A. A contient maintenant 6 éléments, car B en avait 6.

Je veux que l'original 2 soit toujours à la fin après le dernier relevé en C++. J'utiliserais la copie avec des objets. Quel est l'équivalent Java?

Ajouté: OK J'ai laissé quelque chose pour expliquer cela. MyObjectsList ne contient pas HashMap, il est dérivé d'une classe MyBaseOjbectsList qui comprend le membre HashMap et MyObjectsList étend MyBaseOjbectsList. Cela fait-il une différence?

106
user691305

Si vous voulez une copie de HashMap, vous devez en créer une nouvelle avec.

myobjectListB = new HashMap<Integer,myObject>(myobjectListA);

Cela créera une copie (peu profonde) de la carte.

212
ratchet freak

Vous pouvez aussi utiliser

clone()

Méthode pour copier tous les éléments d'un hashmap vers un autre hashmap

Programme pour copier tous les éléments d'un hashmap à un autre

import Java.util.HashMap;

public class CloneHashMap {    
     public static void main(String a[]) {    
        HashMap hashMap = new HashMap();    
        HashMap hashMap1 = new HashMap();    
        hashMap.put(1, "One");
        hashMap.put(2, "Two");
        hashMap.put(3, "Three");
        System.out.println("Original HashMap : " + hashMap);
        hashMap1 = (HashMap) hashMap.clone();
        System.out.println("Copied HashMap : " + hashMap1);    
    }    
}

source: http://www.tutorialdata.com/examples/Java/collection-framework/hashmap/copy-all-elements-from-one-hashmap-to-another

14
user2236292

La différence réside dans le fait qu'en C++, votre objet se trouve sur la pile, alors qu'en Java, il se trouve dans le tas. Si A et B sont des objets, à tout moment dans Java:

B = A

A et B pointent sur le même objet, donc tout ce que vous faites à A vous faites à B et vice versa.

Utilisez new HashMap() si vous voulez deux objets différents.

Et vous pouvez utiliser Map.putAll(...) pour copier des données entre deux cartes.

11
ControlAltDel

Il y a un petit euphorique (énorme) ici. Si vous voulez copier un HashMap avec des structures imbriquées, HashMap.putAll() le copiera par référence, car il ne sait pas exactement comment copier votre objet. Par exemple:

import Java.util.*;
class Playground {
    public static void main(String[ ] args) {
        Map<Integer, Map<Integer,List<Float>>> dataA = new HashMap<>();
        Map<Integer, Map<Integer,List<Float>>> dataB = new HashMap<>();

        dataA.put(1, new HashMap<>());
        dataB.putAll(dataA);

        assert(dataB.get(1).size() == 0);

        dataA.get(1).put(2, new ArrayList<>());

        if (dataB.get(1).size() == 1) { // true
            System.out.println(
                "Sorry object reference was copied - not the values");
        }
    }
}

Donc, fondamentalement, vous devrez copier les champs vous-même comme ici

List <Float> aX = new ArrayList<>(accelerometerReadingsX);
List <Float> aY = new ArrayList<>(accelerometerReadingsY);

List <Float> gX = new ArrayList<>(gyroscopeReadingsX);
List <Float> gY = new ArrayList<>(gyroscopeReadingsY);

Map<Integer, Map<Integer, Float>> readings = new HashMap<>();

Map<Integer,List<Float>> accelerometerReadings = new HashMap<>();
accelerometerReadings.put(X_axis, aX);
accelerometerReadings.put(Y_axis, aY);
readings.put(Sensor.TYPE_ACCELEROMETER, accelerometerReadings);

Map<Integer,List<Float>> gyroscopeReadings = new HashMap<>();
gyroscopeReadings.put(X_axis, gX);
gyroscopeReadings.put(Y_axis, gY);
readings.put(Sensor.TYPE_GYROSCOPE, gyroscopeReadings);
6
murt

En Java, quand vous écrivez:

Object objectA = new Object();
Object objectB = objectA;

objectA et objectB sont identiques et indiquent la même référence. Changer l'un changera l'autre. Donc, si vous changez l'état de objectA (pas sa référence) _ objectB reflétera également ce changement.

Cependant, si vous écrivez:

objectA = new Object()

Ensuite, objectB pointe toujours sur le premier objet que vous avez créé (original objectA) alors que objectA pointe maintenant sur un nouvel objet.

4
assylias

Comme cette question est toujours sans réponse et que j'avais un problème similaire, je vais essayer d'y répondre. Le problème (comme d’autres déjà mentionnés) est que vous copiez simplement des références dans le même objet et qu’une modification sur la copie modifiera également l’objet Origin. Vous devez donc copier l'objet (votre valeur de carte) lui-même. Le moyen le plus simple consiste à faire en sorte que tous vos objets implémentent l'interface sérialisable. Ensuite, sérialisez et désérialisez votre carte pour en obtenir une copie réelle. Vous pouvez le faire vous-même ou utiliser le SerializationUtils # clone () d'Apache commons que vous pouvez trouver ici: https://commons.Apache.org/proper/commons-lang/javadocs/api-2.6/org/ Apache/commons/lang/SerializationUtils.html Sachez que c’est l’approche la plus simple, mais c’est une tâche coûteuse de sérialiser et de désérialiser beaucoup d’objets.

2
KIC

Si nous voulons copier un objet en Java, nous devons envisager deux possibilités: a copie superficielle et une copie complète.

Le copie superficielle est l'approche utilisée lorsque nous copions uniquement les valeurs de champ. Par conséquent, la copie peut dépendre de l'objet d'origine. Dans l'approche copie profonde, nous nous assurons que tous les objets de l'arborescence sont copiés en profondeur, de sorte que la copie ne dépend d'aucun objet existant antérieur susceptible de changer.

Cette question est la définition parfaite pour l’application de l’approche copie profonde.

Premièrement, si vous avez une simple carte HashMap<Integer, List<T>>, nous créons simplement une solution de contournement comme celle-ci. Création d'une nouvelle instance de List<T>.

public static <T> HashMap<Integer, List<T>> deepCopyWorkAround(HashMap<Integer, List<T>> original)
{
    HashMap<Integer, List<T>> copy = new HashMap<>();
    for (Map.Entry<Integer, List<T>> entry : original.entrySet()) {
        copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    return copy;
}

Celui-ci utilise la méthode Stream.collect() pour créer la carte de clonage, mais utilise la même idée que la méthode précédente.

public static <T> Map<Integer, List<T>> deepCopyStreamWorkAround(Map<Integer, List<T>> original)
{
    return original
            .entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey, valueMapper -> new ArrayList<>(valueMapper.getValue())));
}   

Mais, si les instances à l'intérieur de T sont également objets mutables, nous avons un gros problème. Dans ce cas, une copie profonde réelle est une alternative qui résout ce problème. Son avantage est qu'au moins chaque objet mutable dans le graphe d'objet est copié de manière récursive. Comme la copie ne dépend d’aucun objet mutable créé précédemment, elle ne sera pas modifiée par accident, comme nous l’avons vu avec la copie superficielle.

Pour résoudre le problème, cette implémentation en copie profonde fera le travail.

public class DeepClone
{
    public static void main(String[] args)
    {
        Map<Long, Item> itemMap = Stream.of(
                entry(0L, new Item(2558584)),
                entry(1L, new Item(254243232)),
                entry(2L, new Item(986786)),
                entry(3L, new Item(672542)),
                entry(4L, new Item(4846)),
                entry(5L, new Item(76867467)),
                entry(6L, new Item(986786)),
                entry(7L, new Item(7969768)),
                entry(8L, new Item(68868486)),
                entry(9L, new Item(923)),
                entry(10L, new Item(986786)),
                entry(11L, new Item(549768)),
                entry(12L, new Item(796168)),
                entry(13L, new Item(868421)),
                entry(14L, new Item(923)),
                entry(15L, new Item(986786)),
                entry(16L, new Item(549768)),
                entry(17L, new Item(4846)),
                entry(18L, new Item(4846)),
                entry(19L, new Item(76867467)),
                entry(20L, new Item(986786)),
                entry(21L, new Item(7969768)),
                entry(22L, new Item(923)),
                entry(23L, new Item(4846)),
                entry(24L, new Item(986786)),
                entry(25L, new Item(549768))
        ).collect(entriesToMap());


        Map<Long, Item> clone = DeepClone.deepClone(itemMap);
        clone.remove(1L);
        clone.remove(2L);

        System.out.println(itemMap);
        System.out.println(clone);
    }

    private DeepClone() {}

    public static <T> T deepClone(final T input)
    {
        if (input == null) return null;

        if (input instanceof Map<?, ?>) {
            return (T) deepCloneMap((Map<?, ?>) input);
        } else if (input instanceof Collection<?>) {
            return (T) deepCloneCollection((Collection<?>) input);
        } else if (input instanceof Object[]) {
            return (T) deepCloneObjectArray((Object[]) input);
        } else if (input.getClass().isArray()) {
            return (T) clonePrimitiveArray((Object) input);
        }

        return input;
    }

    private static Object clonePrimitiveArray(final Object input)
    {
        final int length = Array.getLength(input);
        final Object output = Array.newInstance(input.getClass().getComponentType(), length);
        System.arraycopy(input, 0, output, 0, length);
        return output;
    }

    private static <E> E[] deepCloneObjectArray(final E[] input)
    {
        final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length);
        for (int i = 0; i < input.length; i++) {
            clone[i] = deepClone(input[i]);
        }

        return clone;
    }

    private static <E> Collection<E> deepCloneCollection(final Collection<E> input)
    {
        Collection<E> clone;
        if (input instanceof LinkedList<?>) {
            clone = new LinkedList<>();
        } else if (input instanceof SortedSet<?>) {
            clone = new TreeSet<>();
        } else if (input instanceof Set) {
            clone = new HashSet<>();
        } else {
            clone = new ArrayList<>();
        }

        for (E item : input) {
            clone.add(deepClone(item));
        }

        return clone;
    }

    private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map)
    {
        Map<K, V> clone;
        if (map instanceof LinkedHashMap<?, ?>) {
            clone = new LinkedHashMap<>();
        } else if (map instanceof TreeMap<?, ?>) {
            clone = new TreeMap<>();
        } else {
            clone = new HashMap<>();
        }

        for (Map.Entry<K, V> entry : map.entrySet()) {
            clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
        }

        return clone;
    }
}
2
Teocci

Depuis Java 10, il est possible d'utiliser

Map.copyOf

pour créer une copie peu profonde , qui est également immuable. (Voici sa Javadoc ). Pour une copie complète , comme mentionné dans ce répondre , vous avez besoin d'un mappeur de valeurs pour créer une copie sécurisée des valeurs . Vous n'avez pas besoin de copier les clés , car elles doivent être immuables .

0
xuesheng

Depuis que le PO a indiqué qu’il n’avait pas accès à la classe de base à l’intérieur de laquelle existe un HashMap - j’ai bien peur que très peu d’options soient disponibles.

Un moyen (extrêmement lent et gourmand en ressources) d’effectuer une copie complète d’un objet dans Java consiste à abuser de l’interface 'Serializable', que de nombreuses classes étendent intentionnellement - ou involontairement -, puis l’utilisent pour sérialiser votre contenu. classe à ByteStream. Lors de la désérialisation, vous aurez une copie complète de l'objet en question.

Un guide pour cela peut être trouvé ici: https://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

0
Felteh

Ce que vous attribuez à un objet, tout ce que vous faites est de copier le référence vers l’objet, pas son contenu. Ce que vous devez faire, c'est prendre votre objet B et copier manuellement le contenu de l'objet A dans celui-ci.

Si vous le faites souvent, vous pouvez envisager d'implémenter une méthode clone() sur la classe qui créera un nouvel objet du même type et copiera tout son contenu dans le nouvel objet.

0
zigdon