Поведение HashMap Copy я не могу понять - PullRequest
5 голосов
/ 20 октября 2011

У меня проблемы с получением отдельной копии моих HashMaps. Под этим я подразумеваю, что после того, как я сделал копию оригинала, изменение одного не меняет другого.

У меня есть два HashMaps в этом формате:

HashMap<String, List<String> one = new HashMap<String, List<String>();
HashMap<String, List<String> two = new HashMap<String, List<String>();

Я вызываю следующую функцию ниже (getTabSetDifferences), передавая один и два, как и ожидалось, если есть некоторые различия, эти значения будут удалены из HashMap и это будет отличаться от того, что было передано для теста.

Я хочу, чтобы они остались без изменений, поэтому попытался ввести:

getTabSetDifferences((HashMap)one.clone(), (HashMap)two.clone())

Это все еще изменило оригиналы, поэтому я создал еще две хеш-карты в том же формате и клонировал им одну и две, я использовал новые хеш-карты для передачи в, и оригинал все еще был изменен.

Я тогда попробовал:

HashMap<String, List<String>> holdOne = new HashMap<String, List<String>>();
holdOne.putAll(one);

HashMap<String, List<String>> Holdtwo = new HashMap<String, List<String>>();
holdTwo.putAll(two);

Теперь я могу сделать что-то вроде:

holdTwo.remove(key);

и оригинал не изменяется, но если я вызову метод с holdOne и holdTwo, он все равно изменит оригинал с одной и двумя хэш-картами, не должны ли они остаться? Метод работает, и находит различия, которые я хочу, и возвращается. Но мне все еще нужно, чтобы исходные два хеш-карты были такими, какими они были, но независимо от того, какие Как я называю, все изменения, которые вносятся в holdOne и holdTwo, изменяют оригиналы. Это ожидаемое поведение? Если да, то как правильно чтобы получить копию хеш-карты, которая не привязана к нему.

getTabSetDifferences(holdOne, holdTwo);

public HashMap<String, List<String>> getTabSetDifferences(HashMap<String, List<String>> hmMain, HashMap<String, List<String>> hmSecond)   {
    HashMap<String, List<String>> hmDifferences = new HashMap<String, List<String>>();
    for (Map.Entry<String, List<String>> entry : hmMain.entrySet()) {
        if(hmSecond.containsKey(entry.getKey())) {
            entry.getValue().removeAll(hmSecond.get(entry.getKey()));
            if (entry.getValue().size() > 0)
                hmDifferences.put(entry.getKey(), entry.getValue());
        }
        else {
            hmDifferences.put(entry.getKey(), entry.getValue());
        }
    }
    return hmDifferences;
}

Ответы [ 3 ]

2 голосов
/ 20 октября 2011

Метод клонирования не делает глубокую копию.

У вас есть 2 варианта.

  1. создать метод глубокого копирования.
  2. Используйте одну из реализаций Map из пакета java.util.concurrent, например copyOnWrite
2 голосов
/ 20 октября 2011

Если вы копируете список в виде списка (т.е. копируете его в области списка, а не в какой-либо реализации более низкого уровня), то поведение указателя будет видно ... Однако, если вы копируете из одного списка в новый список,тогда эти строковые объекты независимы.

Java-метод клонирования не следует использовать в ожидании того, что он возвратит различные глубокие копии объекта - неизменность не является центральной концепцией работы клона.

Я согласен с вышеизложеннымкомментарий: либо используйте мультикарту в библиотеке, например, в guava, либо в коллекциях Google, либо просто очень внимательно относитесь к копированию и копируйте только на примитивных уровнях (никогда не копируйте коллекцию и не ожидайте, что она будет независимой), если только выЯ проверил это явно.

2 голосов
/ 20 октября 2011

Я подозреваю, что вы копируете только ключи / значения.Это не будет создавать копии списков.

Возможно, MultiMap от Guava - это то, что вам нужно?

...