2013年11月16日土曜日

【Java】HashMapを「=」でコピーすると参照元のマップオブジェクトのデータも削除される

まずはサンプルソースと結果を御覧ください

■サンプルソースコード1
package com.kakakikikeke.sample.test;

import java.util.HashMap;

public class Test {

 public static void main(String[] args) {
  HashMap<String, String> map1 = new HashMap<String, String>();
  map1.put("key1", "value");
  map1.put("key2", "value");
  System.out.println("* before");
  for (String key: map1.keySet()) {
   System.out.println(key);
   System.out.println(map1.get(key));
  }

  HashMap<String, String> map2 = map1;
  map2.remove("key1");
  System.out.println("* after");
  for (String key: map1.keySet()) {
   System.out.println(key);
   System.out.println(map1.get(key));
  }
 }

}

■結果1
* before
key2
value
key1
value
* after
key2
value

■サンプルソースコード2
package com.kakakikikeke.sample.test;

import java.util.HashMap;

public class Test {

 public static void main(String[] args) {
  HashMap<String, String> map1 = new HashMap<String, String>();
  map1.put("key1", "value");
  map1.put("key2", "value");
  System.out.println("* before");
  for (String key: map1.keySet()) {
   System.out.println(key);
   System.out.println(map1.get(key));
  }

  HashMap<String, String> map2 = new HashMap<String, String>(map1);
  map2.remove("key1");
  System.out.println("* after");
  for (String key: map1.keySet()) {
   System.out.println(key);
   System.out.println(map1.get(key));
  }
 }

}

■結果2
* before
key2
value
key1
value
* after
key2
value
key1
value

■考察
サンプルソースコード1では作成したmap1を「=」でmap2に代入しています
そのあとにmap2に対してremoveを実行します
すると、代入したmap1からデータが削除されていることがわかります

これを回避する方法としてサンプルソースコード2を見て下さい
ソースコード2で緑色が付いている部分でmap1からmap2にオブジェクトをコピーしています
ソースコード1では単純に「=」で代入してましたが、今度はHashMapのコンストラクタの引数としてmap1を指定しています
単純にmap2のオブジェクトを新規で作成しているだけですが、サンプルソースコード2のほうはmap2側のデータをremoveしてもmap1側には影響していません

上記を踏まえてこの現象をまとめると
  • ソースコード1はmap1とmap2が同じデータを見ているためmap1側にも影響があった
  • ソースコード2はmap1と全く同じデータを持つmap2オブジェクトを新規で作成したためmap1側には影響がなかった
ということになります

考えてみると当たり前かもしれませんが、HashMapをコピーしたいという場合に結構陥りそうな罠なのかと思いました

0 件のコメント:

コメントを投稿