在我的实现中,我有一个类A,它覆盖equals(Object)和hashCode()。但我有一个小小的疑问,即在向HashSet / HashMap添加A的实例时,hashCode()的值是x,之后相同的hashCode()的值更改为y。它会影响什么吗?
答案 0 :(得分:7)
哈希码在添加到地图/集后不得更改。它可以在此之前进行更改,但如果没有更改它通常会使类型更容易使用。
如果哈希码发生变化,则不会在map / set中找到密钥,因为即使它最终在同一个桶中,哈希码也会先被更改。
答案 1 :(得分:3)
如果对象包含在hashCode()
/ equals()
等中,HashMap
或HashSet
的返回值发生变化,则行为未定义(您可以获得各种奇怪的行为)。因此,当对象包含在此类集合等中时,必须避免密钥的这种变异。
最好只使用不可变对象作为键(或将它们放在HashSet
等中)。实际上,例如python不允许将可变对象用作映射中的键。在Java中使用可变对象作为键是允许/通用的,但在这种情况下,建议使这些对象“有效地不可变”。即实例化后,根本不要更改此类对象的状态。
举一个例子,使用列表作为Map中的键通常被认为是可以的,但是你应该避免在你的应用程序的任何一点改变这样的列表,以避免被令人讨厌的错误所困扰。
只要在对象位于容器中时不更改hashCode()
和equals()
的返回值,您就可以在纸上完成了。但是人们可能很容易引入令人讨厌的,难以发现的错误,所以最好完全避免这种情况。
答案 2 :(得分:2)
是的,对象的哈希码在其生命周期内不得更改。如果是,则需要通知容器(如果可能的话);否则你会会得到错误的结果。
编辑:正如所指出的,它取决于容器。显然,如果容器从不使用您的hashCode
或equals
方法,则不会出现任何问题。但是一旦它试图比较事物的平等(所有地图和集合),你就会遇到麻烦。
答案 3 :(得分:1)
是。很多人在这里回答了这个问题,我只是想说一个类比。散列代码类似于基于散列的集合中的地址:
想象一下,您以“Mike”的名义入住酒店,然后在支票据上将您的名字改为“GreatMike”。然后当有人用你的名字“迈克”找你时,他再也找不到你了。