142 votes

Copier une table de hachage en Java

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

HashMap<Integer,myObject> myobjectHashMap

Une classe appelée myobjectsList

Ensuite, je le fais

myobjectsListA = new myobjectsList();
myobjectsListB = new myobjectsList();

ensuite : Ajouter quelques éléments hashmap à A (comme 2)

ensuite :

myobjectListB = myobjectListA; //B has 2

ensuite : Ajouter des éléments hashmap à A (comme 4 de plus)

ensuite : renvoyer A aux éléments stockés dans B

myobjectListA = myobjectListb;

Mais lorsque je fais cela, B grandit avec A alors que j'ajoute des éléments hashmap à A. A contient maintenant 6 éléments parce que B en avait 6.

Je veux que A ait toujours les 2 originaux à la fin après la dernière affectation. En C++, j'utiliserais copy avec des objets, quel est l'équivalent en Java ?

Ajouté : OK, j'ai oublié quelque chose dans l'explication. MyObjectsList ne contient pas de HashMap, il est dérivé d'une classe MyBaseOjbectsList qui possède le membre HashMap et MyObjectsList s'étend MyBaseOjbectsList . Cela fait-il une différence ?

6voto

Teocci Points 1441

Si nous voulons copier un objet en Java, deux possibilités s'offrent à nous : a copie superficielle et un copie approfondie .

En copie superficielle est l'approche à adopter lorsque nous ne copions que les valeurs des champs. Par conséquent, la copie peut dépendre de l'objet original. Dans l'approche copie approfondie nous nous assurons que tous les objets de l'arbre sont copiés en profondeur, de sorte que la copie ne dépende pas d'un objet existant antérieur susceptible d'être modifié.

Cette question est la définition parfaite de l'application de la copie approfondie l'approche.

Tout d'abord, si vous avez un simple HashMap<Integer, List<T>> Nous créons alors une solution de contournement comme celle-ci. En créant une nouvelle instance de l'élément 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 Stream.collect() pour créer la carte du clone, mais elle 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, la copie intégrale est une alternative qui résout ce problème. Son avantage est qu'au moins chaque objet mutable dans le graphe d'objets est copié récursivement. Étant donné que la copie ne dépend d'aucun objet mutable qui a été créée plus tôt, elle ne sera pas modifiée par accident comme nous l'avons vu avec la copie superficielle.

Pour résoudre ce problème, les implémentations de la copie en profondeur feront 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;
    }
}

4voto

assylias Points 102015

En Java, lorsque vous écrivez :

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

objectA y objectB sont identiques et renvoient à la même référence. La modification de l'un entraîne la modification de l'autre. Ainsi, si vous changez l'état de objectA (pas sa référence) objectB reflétera également ce changement.

Toutefois, si vous écrivez :

objectA = new Object()

Entonces objectB pointe toujours vers le premier objet que vous avez créé (original objectA ) tout en objectA pointe désormais vers un nouvel objet.

1voto

KIC Points 548

Puisque cette question est toujours sans réponse et que j'ai eu un problème similaire, je vais essayer d'y répondre. Le problème (comme d'autres l'ont déjà mentionné) est que vous ne faites que copier des références au même objet et que, par conséquent, une modification sur la copie modifiera également l'objet d'origine. Il faut donc copier l'objet (la valeur de la carte) lui-même. La façon la plus simple de le faire est de faire en sorte que tous vos objets implémentent l'interface sérialisable. Ensuite, sérialisez et désérialisez votre carte pour obtenir une vraie copie. 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 Mais attention, il s'agit de l'approche la plus simple, mais la sérialisation et la désérialisation d'un grand nombre d'objets est une tâche coûteuse.

1voto

yoAlex5 Points 2350

Java Copie d'un tableau de correspondance (HashMap)

Java prend en charge superficielle concept de copie (peu approfondi)

Vous pouvez l'archiver en utilisant :

  • constructeur
  • clone()
  • putAll()

0voto

zigdon Points 8753

Lorsque vous affectez un objet à un autre, vous ne faites que copier l'élément référence à l'objet et non à son contenu. Ce que vous devez faire, c'est prendre votre objet B et copier manuellement le contenu de l'objet A dans cet objet.

Si vous le faites souvent, vous pourriez envisager de mettre en place un système de gestion de l'information. clone() sur la classe qui créera un nouvel objet du même type et copiera tout son contenu dans le nouvel objet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X