1. 概要

このチュートリアルでは、 HashMap の浅いコピーと深いコピーの概念を、JavaでHashMapをコピーするいくつかの手法とともに説明します。

また、特定の場合に役立つ外部ライブラリのいくつかについても検討します。

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. HashMap API

3.1. HashMap Constructorを使用する

HashMap のパラメーター化されたコンストラクター HashMap(Map <? Kを拡張しますか? 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()メソッドを使用できます。このメソッドは、すべてのマッピングを1つのステップで浅くコピーします。

HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);    

一致するキーがある場合、 put()とputAll()が値を置き換えることに注意してください。

HashMap のコンストラクター、 clone()、および putAll()の実装を見ると、すべてが見つかることにも注目してください。それらのうち、エントリをコピーするために同じ内部メソッドを使用します— putMapEntries()

4. HashMapをコピーするJava8 StreamAPIを使用する

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

Guava Maps、を使用すると、ソートされたbiマップとともに、不変のマップを簡単に作成できます。 これらのマップのいずれかの不変で浅いコピーを作成するには、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 Lang

現在、Javaには組み込みのディープコピー実装がありません。したがって、ディープコピーを作成するには、 clone()メソッドをオーバーライドするか、シリアル化を使用できます-逆シリアル化手法。

Apache Commonsには、ディープコピーを作成するための clone()メソッドを備えたSerializationUtilsがあります。 このため、ディープコピーに含まれるクラスは、Serializableインターフェイスを実装する必要があります。

public class Employee implements Serializable {
    // implementation details
}

HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);

7. 結論

このクイックチュートリアルでは、 HashMap の浅いコピーと深いコピーの概念とともに、HashMapをJavaにコピーするさまざまな手法を見てきました。

また、浅いコピーと深いコピーを作成するのに非常に便利な外部ライブラリのいくつかを調べました。

これらの実装の完全なソースコードと単体テストは、GitHubプロジェクトで入手できます。