Как скопировать HashMap (не мелкой копии) в Java
Мне нужно сделать копию HashMap<Integer, List<MySpecialClass> >
, но когда я что-то меняю в копии, я хочу, чтобы оригинал оставался прежним. то есть когда я удаляю что-то из List<MySpecialClass>
из копии, он остается в List<MySpecialClass>
в оригинале.
Если я правильно понимаю, эти два метода создают только мелкую копию, которая не то, что я хочу:
mapCopy = new HashMap<>(originalMap);
mapCopy = (HashMap) originalMap.clone();
Я прав?
Есть ли лучший способ сделать это, чем просто перебирать все ключи и все элементы списка и скопировать их вручную?
Ответы
Ответ 1
Вы правы, что мелкая копия не будет соответствовать вашим требованиям. Он будет иметь копии List
с вашей исходной карты, но те List
будут ссылаться на те же объекты List
, так что изменение в List
от одного HashMap
появится в соответствующем List
от другого HashMap
.
В Java нет глубокого копирования для HashMap
, поэтому вам все равно придется перебирать все записи и put
их в новом HashMap
. Но вы также должны делать копию List
каждый раз. Что-то вроде этого:
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;
}
Если вы хотите изменить свои индивидуальные объекты MySpecialClass
и чтобы изменения не отражались в List
вашего скопированного HashMap
, вам также нужно будет создать новые копии.
Ответ 2
Это, к сожалению, требует итерации. Но это довольно тривиально с потоками Java 8:
mapCopy = map.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue()));
Ответ 3
Вы делаете копию самого HashMap, поэтому изменение копии HashMap не приведет к изменению исходного HashMap (т.е. добавлению или удалению записей), но поскольку объекты, которые вы сохранили, не являются примитивными типами, список, который вы извлекаете с помощью данная клавиша будет одинаковой, независимо от того, извлекается ли она с первой или второй карты.
Таким образом, есть еще только одна копия этого списка, на которую ссылаются обе карты: изменение списка меняет его независимо от того, какую ссылку вы используете для доступа к ней.
Если вы хотите, чтобы фактический список был отдельной копией, вам нужно будет сделать так, как вы сказали: перейдите по набору записей HashMap и создайте копию каждого списка вручную, добавив его на новую карту по мере продвижения.
Если есть лучший способ, я не знаю, что это такое.
Ответ 4
Вы можете попробовать глубокое клонирование. Посмотрите, например, на https://code.google.com/p/cloning/
Ответ 5
Последовательно сериализовать json и десериализовать:
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());
Для специальных классов вам может понадобиться написать пользовательский десериализатор.