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

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

问题描述

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

 地图< Set< Thing& Val>地图; 

当我查询map.containsKey(myBunchOfThings)时,它返回false,我不明白为什么。我可以遍历密钥集中的每个密钥,并验证是否有一个密钥(1)具有相同的hashCode,(2)是等于()到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。); //它输出这个
}
}

我从根本上误解了containsKey的合同吗?使用集合(或更一般的集合)作为映射的键有秘密吗?

Map java文档说:

$ b
$ b


注意:如果
可变对象用作映射键,必须非常小心
未指定映射的行为
如果一个对象的值改变了
,影响等于
的比较,而对象是一个关键字
在映射中的一个特殊情况
禁止是不是
允许一个地图包含
本身作为一个键。虽然
允许一个地图包含
本身作为一个值,极端警告是
建议:equals和hashCode
方法在
a这种地图上不再被很好地定义。


我知道这个问题,但从来没有做过测试,直到现在。我再详述一下:

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

设置< String> key1 = new HashSet< String>();
key1.add(hello);

设置< String> key2 = new HashSet< String>();
key2.add(hello2);

设置< 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.containingKey(key1)); // true
System.out.println(map.containsKey(key2)); // true
System.out.println(map.containsKey(key2clone)); // true

key2 地图不再包含它了。我们可以认为映射在添加数据时索引数据,然后我们预期它仍然包含key2克隆(标记为 * 的行)。但很滑稽,这不是这样。



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



我想这是你的情况。


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

Map<Set<Thing>, Val> map;

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.
  }
}

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 should not be mutated while used in the map. The Map java doc says:

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

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

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

I guess that's what happens in your case.

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

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