HashMap值是否必须是不可变的?

时间:2014-11-10 03:15:59

标签: java collections hashmap

我知道HashMap中的键需要是不可变的,或者至少确保它们的哈希码(hashCode())不会改变或与另一个具有不同状态的对象冲突。

但是,存储在HashMap中的值是否需要与上面的*相同?为什么或为什么不呢?

*我们的想法是能够改变值(例如在其上调用setter),而不会影响以后使用不可变键从HashMap中检索它们的能力。如果值发生变异,会破坏与键的关联吗?

我的问题主要是关于Java,但欢迎其他语言的答案。

5 个答案:

答案 0 :(得分:2)

没有。通常,散列映射数据结构的特征不依赖于该值。使密钥不可变是很重要的,因为底层数据结构是在插入时使用密钥的哈希构建的。底层数据结构旨在提供基于此哈希的某些属性(相对快速查找,快速删除,快速删除等等)。如果要更改此哈希,则基于已更改的哈希具有这些良好属性的数据结构将无效。如果你需要"修改"关键的一种通用方法是删除旧密钥并重新插入新密钥。

答案 1 :(得分:2)

HashMap的值不需要是不可变的。地图通常不关心值发生了什么(除非它是ConcurrentHashMap),只关注值在内存中的位置。

在ConcurrentHashMap的情况下,值的可变性不会受到影响,但是如果地图不关心"则会过于宽泛。这个价值会发生什么。即使在地图更新时允许并发,也可以操纵地图指向的值,而不会影响不可变键。

答案 2 :(得分:2)

RE:如果值发生变异,是否会破坏与键的关联?

没有

Map返回给定键的对象引用。该键总是指向同一个对象引用。以某种方式更改对象(即更改其实例变量)将影响检索该对象的能力。

答案 3 :(得分:1)

没有值不需要是不可变的,但可以是非常好的练习。这当然取决于您的用例。

这是一个不可变性非常重要的用例:我最近遇到了一个bug。条目放在缓存中(由HashMap支持)。之后,检索并更改了此条目。由于该值是可变的(即允许更改),因此下一个条目检索仍然具有前一个检索器所做的编辑。这是一个问题,因为在我的用例中,缓存数据不应该改变。

考虑这个例子:

    Class Foo {
       int a;
       public Foo(int a) { this.a = a; }
       public void setA(int x) { this.a = a; }
    }

    Map<String, Foo> data = getFooMap();
    Foo foo = new Foo(17);
    data.put("entry1", foo);

    Foo entry1 = map.get("entry1);
    System.out.println(entry1.a);   // prints "17"

    entry1.setA(18); 

...

   Foo entry1 = map.get("entry1);
   System.out.println(entry1.a);   // prints "18"  

答案 4 :(得分:1)

不是真的。拥有一个可变的密钥将带来重大问题,但你提出的价值并不重要。如果值是一个可变对象并且一个修改了它,那么当然也会更新该值(但这与Hashmap无关)。