如何在 Java Maps 中使用 Sets 作为键 [英] How to use Sets as keys in Java Maps

查看:14
本文介绍了如何在 Java Maps 中使用 Sets 作为键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Set 作为键类型的 Map,如下所示:

I have a Map that uses a Set for the key type, like this:

Map<Set<Thing>, Val> map;

当我查询 map.containsKey(myBunchOfThings) 时,它返回 false,我不明白为什么.我可以遍历键集中的每个键并验证有一个键 (1) 具有相同的 hashCode,并且 (2) 等于 () 到 myBunchOfThings.

When I query map.containsKey(myBunchOfThings), it returns false, and I don't understand why. I can iterate through each key in the keyset and verify there is a key that (1) has the same hashCode, and (2) is equals() to myBunchOfThings.

System.out.println(map.containsKey(myBunchOfThings)); // false.
for (Set<Thing> k : map.keySet()) {
  if (k.hashCode() == myBunchOfThings.hashCode() && k.equals(myBunchOfThings) {
     System.out.println("Fail at life."); // it prints this.
  }
}

我是否只是从根本上误解了 containsKey 的合同?使用集合(或更一般地说,集合)作为映射的键有什么秘诀吗?

Do I just fundamentally misunderstand the contract for containsKey? Is there a secret to using sets (or more generally, collections) as keys to maps?

推荐答案

Key 在地图中使用时不应改变.Map java 文档说:

Key should not be mutated while used in the map. The Map java doc says:

注意:必须非常小心,如果可变对象用作映射键.未指定地图的行为如果对象的值发生变化以一种影响平等的方式对象是键时的比较在地图中.这是一个特例禁止是它不是允许地图包含本身就是一把钥匙.虽然是允许地图包含本身作为一个值,极其谨慎的是建议:equals 和 hashCode方法不再明确定义一张这样的地图.

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on a such a map.

我知道这个问题,但直到现在才进行测试.我再详细说明一下:

I knew this issue, but never made the test until now. I elaborate then a bit more:

   Map<Set<String>, Object> map  = new HashMap<Set<String>, Object>();

   Set<String> key1 = new HashSet<String>();
   key1.add( "hello");

   Set<String> key2 = new HashSet<String>();
   key2.add( "hello2");

   Set<String> key2clone = new HashSet<String>();
   key2clone.add( "hello2");

   map.put( key1, new Object() );
   map.put( key2, new Object() );

   System.out.println( map.containsKey(key1)); // true
   System.out.println( map.containsKey(key2)); // true
   System.out.println( map.containsKey(key2clone)); // true

   key2.add( "mutate" );

   System.out.println( map.containsKey(key1)); // true
   System.out.println( map.containsKey(key2)); // false
   System.out.println( map.containsKey(key2clone)); // false (*)

   key2.remove( "mutate" );

   System.out.println( map.containsKey(key1)); // true
   System.out.println( map.containsKey(key2)); // true
   System.out.println( map.containsKey(key2clone)); // true

key2 变异后,地图不再包含它.我们可以认为地图在添加数据时索引"了数据,然后我们期望它仍然包含 key2 克隆(用 * 标记的行).但有趣的是,事实并非如此.

After key2 is mutated, the map does not contain it anymore. We could think that the map "indexes" the data when it's added and we would then expect that it still contains the key2 clone (line marked with *). But funny enough, this is not the case.

因此,正如 java 文档所说,不应改变键,否则行为未指定.期间.

So, as the java doc says, keys should not be mutated otherwise the behavior is unspecified. Period.

我想这就是你的情况.

这篇关于如何在 Java Maps 中使用 Sets 作为键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆