我可以将HashSet作为HashMap中的键吗?如果没有建议替代方案

时间:2012-03-19 16:20:49

标签: java hashmap set hashset

编辑:现在正确解释了问题。

我有一个hashmap,我想存储一起看到的单词组(键)和它们在一起看到的行(值)。这是我提出的结构:

HashMap<HashSet<String>, HashSet<Integer>> hm= ...
输入

  1. 芒果,香蕉,苹果

  2. apple,banana

  3. 桃子,海象

  4. 海象,桃子

  5. 当我逐行阅读本文时,我会从行中的单词组合中创建新的临时键(尚未插入到hashmap中的哈希集)。每个临时密钥是该行中单词的子集的哈希集。如果我的hashmap中已存在临时密钥,我将通过

    检查
    if(hashmap.containsKey(hashset))
    

    我只是将新行添加到该键的相应值,如果没有,我在hashmap中创建一个新条目并处理它。

    我决不改变现有密钥。我只更新了hasmmap中的相应值。

    我的hashmap在读取文件的最后应该看起来像这样

    [apple,banana] = [1,2]

    [peach,walrus] = [3,4]

    ...

    问题在于

    if(hashmap.containsKey(hashset))
    

    一段代码并不总是检测现有密钥。为什么是这样?这种结构不允许吗?

    谢谢

3 个答案:

答案 0 :(得分:7)

这应该可行,但您需要注意键的可变性。如果您更改其中一个键的内容,其哈希码将会更改,并且您的地图将开始执行奇怪的操作。来自Map的javadoc:

  

注意:如果将可变对象用作地图,则必须非常小心   键。如果对象的值,则不指定映射的行为   以一种影响等于比较的方式改变   对象是地图中的关键。这一禁令的一个特例是   地图不允许将自己包含为关键字。虽然它   允许地图将自己包含为一个值,极其谨慎   建议:equals和hashCode方法不再明确定义   在这样的地图上。

为避免这种情况,请在创建时立即用Collections.unmodifiableSet()包裹密钥,或者只使用Guava中的ImmutableSet

答案 1 :(得分:4)

您可以,但是一旦您将HashSet添加为HashMap的密钥,就不应该再次修改它,因为HashSet.hashCode()可能会发生变化而您永远找不到你的HashSet了。换句话说,如果您正在做类似的事情,请确保您的密钥是不可变的HashSets(另请参阅Matt's answer here

另一种方法是使用MultiKeyMap以及来自MultiKeycommons collections

答案 2 :(得分:1)

@Lukas和@Matt很好地解释了你所遇到的问题 我认为你可以通过使用扩展或使用装饰器模式来创建Hashset,以一种独立于内容的方式覆盖equalshashCode

通过这种方式,您可以避免仅针对特定问题引入第三方jar的依赖性