我知道HashMap中的键需要是不可变的,或者至少确保它们的哈希码(hashCode()
)不会改变或与另一个具有不同状态的对象冲突。
但是,存储在HashMap中的值是否需要与上面的*相同?为什么或为什么不呢?
*我们的想法是能够改变值(例如在其上调用setter),而不会影响以后使用不可变键从HashMap中检索它们的能力。如果值发生变异,会破坏与键的关联吗?
我的问题主要是关于Java,但欢迎其他语言的答案。
答案 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无关)。