1. Обзор
В этом руководстве мы рассмотрим концепцию поверхностной и глубокой копии HashMap, а
также несколько методов копирования HashMap
в Java.
Мы также рассмотрим некоторые внешние библиотеки, которые могут помочь нам в конкретных случаях.
2. Мелкие и глубокие копии
Во-первых, давайте разберемся с концепцией мелких и глубоких копий в HashMaps
.
2.1. Неглубокое копирование
Неглубокая копия HashMap
— это новый HashMap
с сопоставлениями с теми же объектами ключа и значения, что и исходный HashMap
.
Например, мы создадим класс Employee
, а затем карту с экземплярами Employee
в качестве значений:
public class Employee {
private String name;
// constructor, getters and setters
}
HashMap<String, Employee> map = new HashMap<>();
Employee emp1 = new Employee("John");
Employee emp2 = new Employee("Norman");
map.put("emp1", emp1);
map.put("emp2", emp2);
Теперь мы проверим, что исходная карта и ее неглубокая копия являются разными объектами:
HashMap<String, Employee> shallowCopy = // shallow copy implementation
assertThat(shallowCopy).isNotSameAs(map);
Поскольку это поверхностная копия, если мы изменим свойства экземпляра Employee
, это повлияет как на исходную карту, так и на ее поверхностную копию:
emp1.setFirstName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));
2.2. Глубокое копирование
Глубокая копия HashMap
— это новый HashMap
, который глубоко копирует все сопоставления. Поэтому он создает новые объекты для всех ключей, значений и отображений.
Здесь явное изменение сопоставлений (ключ-значение) не повлияет на глубокую копию:
HashMap<String, Employee> deepCopy = // deep copy implementation
emp1.setFirstName("Johny");
assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));
3. API -интерфейс хэш-карты
3.1. Использование конструктора HashMap
C
`Параметризованный конструктор
HashMap
HashMap(Map<? extends K,? extends V> m)` обеспечивает быстрый способ поверхностного копирования всей карты:
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>(originalMap);
3.2. Использование Map.clone()
Подобно конструктору, метод HashMap
# clone
также создает быструю неглубокую копию:
HashMap<String, Employee> shallowCopy = originalMap.clone();
3.3. Использование Map.put()
HashMap можно легко скопировать, перебирая каждую запись и вызывая метод put
()
на другой карте:
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>();
Set<Entry<String, Employee>> entries = originalMap.entrySet();
for (Map.Entry<String, Employee> mapEntry : entries) {
shallowCopy.put(mapEntry.getKey(), mapEntry.getValue());
}
3.4. Использование Map.putAll()
Вместо того, чтобы перебирать все записи, мы можем использовать метод putAll()
, который неглубоко копирует все сопоставления за один шаг:
HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);
Следует отметить, что put()
и putAll()
заменяют значения, если есть соответствующий ключ .
Также интересно отметить, что если мы посмотрим на конструктор HashMap
, реализацию clone()
и putAll()
, мы обнаружим, что все они используют один и тот же внутренний метод для копирования записей — putMapEntries()
.
4. Копирование HashMap
с помощью потокового
API Java 8
Мы можем использовать Java 8 Stream
API для создания мелкой копии HashMap
:
Set<Entry<String, Employee>> entries = originalMap.entrySet();
HashMap<String, Employee> shallowCopy = (HashMap<String, Employee>) entries.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
5. Google Гуава
Используя карты Guava, мы можем легко создавать неизменяемые карты, а также отсортированную и бикарту. Чтобы сделать неизменяемую поверхностную копию любой из этих карт, мы можем использовать метод copyOf
:
Map<String, Employee> map = ImmutableMap.<String, Employee>builder()
.put("emp1",emp1)
.put("emp2",emp2)
.build();
Map<String, Employee> shallowCopy = ImmutableMap.copyOf(map);
assertThat(shallowCopy).isSameAs(map);
6. Язык Apache Commons
Теперь в Java нет встроенных реализаций глубокого копирования. Таким образом, чтобы сделать глубокую копию, мы можем либо переопределить метод clone()
, либо использовать метод сериализации-десериализации.
В Apache Commons есть SerializationUtils
с методом clone()
для создания глубокой копии. Для этого любой класс, который будет включен в глубокую копию, должен реализовать интерфейс Serializable :
public class Employee implements Serializable {
// implementation details
}
HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);
7. Заключение
В этом кратком руководстве мы рассмотрели различные методы копирования HashMap
в Java, а также концепцию поверхностного и глубокого копирования для HashMap
s.
Кроме того, мы изучили некоторые внешние библиотеки, которые весьма удобны для создания поверхностных и глубоких копий.
Полный исходный код этих реализаций вместе с модульными тестами доступен в проекте GitHub .