私がよく理解していれば、2 つのマップ エントリ セット間の対称差を計算しようとしています。
Map<String, Object> map1;
Map<String, Object> map2;
Set<Entry<String, Object>> diff12 = new HashSet<Entry<String, Object>>(map1.entrySet());
Set<Entry<String, Object>> diff21 = new HashSet<Entry<String, Object>>(map2.entrySet());
Set<Entry<String, Object>> result;
diff12.removeAll(map2.entrySet());
diff21.removeAll(map1.entrySet());
diff12.addAll(diff21);
あなたが言及した厄介な動作を考慮して、上記のコードの動作を詳しく見てみましょう。たとえば、上記のリンクから数値例を取得すると、次のようになります。
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
map1.put("d", 4);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("a", 1);
map2.put("d", 4);
map2.put("e", 5);
示されているように差を計算すると、出力は次のようになります。
System.out.println(Arrays.deepToString(diff12.toArray()));
与えます:
[e=5, c=3, b=2]
これが正しい結果です。しかし、次のようにすると:
public class CustomInteger {
public int val;
public CustomInteger(int val) {
this.val = val;
}
@Override
public String toString() {
return String.valueOf(val);
}
}
map1.put("a", new CustomInteger(1));
map1.put("b", new CustomInteger(2));
map1.put("c", new CustomInteger(3));
map1.put("d", new CustomInteger(4));
map2.put("a", new CustomInteger(1));
map2.put("d", new CustomInteger(4));
map2.put("e", new CustomInteger(5));
同じアルゴリズムで次の出力が得られます。
[e=5, a=1, d=4, d=4, b=2, a=1, c=3]
これは正しくありません (そして、ぎこちないと説明されるかもしれません :) )
最初の例では、マップは int 値で満たされ、自動的に Integer 値にボックス化されます。
クラス Integerには、 equalsおよびhashCodeメソッドの独自の実装があります。
クラス CustomInteger はこれらのメソッドを実装しないため、遍在するObject クラスから継承します。
Set インターフェイスのremoveAll メソッドのAPI ドキュメントには、次のように記載されています。
指定されたコレクションに含まれるすべての要素をこのセットから削除します (オプションの操作)。指定されたコレクションもセットである場合、この操作はこのセットを効果的に変更し、その値が 2 つのセットの非対称セットの差になるようにします。
両方のコレクションに含まれる要素を判別するために、removeAll メソッドはコレクション要素の equals メソッドを使用します。
それがキャッチです: Integer の equals メソッドは、2 つの数値が同じ場合に true を返しますが、Object の equals メソッドは、同じオブジェクトである場合にのみ true を返します。
Integer a = 1; //autoboxing
Integer b = new Integer(1);
Integer c = 2;
a.equals(b); // true
a.equals(c); // false
CustomInteger d = new CustomInteger(1);
CustomInteger e = new CustomInteger(1);
CustomInteger f = new CustomInteger(2);
d.equals(e); //false
d.equals(f) // false
d.val == e.val //true
d.val == f.val //false
それでも少しあいまいな場合は、次のチュートリアルを読むことを強くお勧めします。