不可变对象和哈希映射键

19

除了像 String 这样的不变对象以外,诸如 Integer 和其他包装类等是否适合用于哈希表键?

有人能解释一下吗?


1
不用担心。 - Maroun
5
你的意思并不是很清楚。你有具体的担忧吗?如果可变对象可以在改变时影响哈希码,将其用作键值是一个非常糟糕的想法。 - Jon Skeet
你想通过这个实现什么目标? - Suresh Atta
你可能正在寻找这个问题的答案:为什么HashMap中的不可变对象如此有效? - Vishal Zanzrukia
4个回答

20
如果对象是不可变的,它的哈希码就不会改变,这允许缓存不同键的哈希码,从而使整个检索过程非常快。对于可变对象,hashCode() 可能取决于可能更改的字段,如果发生这种情况,则无法在 HashMap 中找到该键(及其值),因为 hashCode() 返回不同的值。

11
你可以在这里找到答案:HashMap在Java中的工作原理

字符串、整数和其他包装器类是HashMap键的自然候选者,其中String是最常用的键,因为String是不可变的、final的,并且覆盖了equals和hashCode()方法。其他包装类也具有类似的属性。不可变性是必需的,以防止用于计算hashCode()的字段发生更改,因为如果键对象在插入和检索期间返回不同的hashCode,则将无法从HashMap获取对象。不可变性最好,因为它还提供其他优点,如线程安全性。如果您只通过使某些字段final来保持hashCode相同,则也可以这样做。由于equals()和hashCode()方法在从HashMap检索值对象时使用,因此重要的是键对象正确地覆盖这些方法并遵循联系。如果不相等的对象返回不同的hashcode,则碰撞的机会将较小,从而提高HashMap的性能。

这里还有一个关于讨论的堆栈:为什么HashMap中的不可变对象如此有效

HashMap的put和get方法都使用了hashcode和equals方法。您需要确保在放置键对象后,始终可以从映射中获取值对象,无论您是否更改了键对象。但是不可变对象就足够好了。


1
如果你可以通过仅将某些字段声明为final来保持hashCode不变,那么你也应该这样做。这是否意味着,如果一个键是可变的,但它的hashCode不依赖于可变属性并保持不变,那么这个可变对象也可以成为一个好的HashMap键? - a Learner
1
我认为你也需要保持equals方法的一致性。否则,当你使用相同的键再次输入条目并更改equals方法的值时,它将不会替换旧值。这是不符合预期的。 - Jacky
@aLearner 如果你查看HashMap的源代码,对你会很有帮助。 - Jacky

3

是的,因为它是不可改变的。

假设我有一个类

MyKey key = new MyKey("shreyansh"); //assume hashCode=1234
myHashMap.put(key, "value");

// Below code will change the key hashCode() and equals()
// but it's location is not changed.
key.setName("jogi"); //assume new hashCode=7890

//below will return null, because HashMap will try to look for key
//in the same index as it was stored but since key is mutated,
//there will be no match and it will return null.
myHashMap.get(new MyKey("shreyansh")); 

当使用关键字“Shreyansh”访问时,它将返回null。


2
如果您的对象是不可变的,并且正确实现了哈希码/相等性,那么您可以放心地将它们用作哈希映射中的键。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接