Java hashCode()是否可以动态更改内容?

Java hashCode()是否可以动态更改内容?,java,Java,在我的实现中,我有一个重写equals(Object)和hashCode()的类a。但我有一个小小的疑问,那就是,在将a的实例添加到HashSet/HashMap时,hashCode()的值是x,之后,同一个hashCode()的值变为y。它会影响什么吗?是的,对象的哈希代码在其生命周期内不得更改。如果有,您需要通知容器(如果可能);否则你会得到错误的结果 编辑:如前所述,它取决于容器。显然,如果容器从不使用hashCode或equals方法,那么就不会出现任何问题。但一旦它尝试比较事物是否相等

在我的实现中,我有一个重写equals(Object)和hashCode()的类a。但我有一个小小的疑问,那就是,在将a的实例添加到HashSet/HashMap时,hashCode()的值是x,之后,同一个hashCode()的值变为y。它会影响什么吗?

是的,对象的哈希代码在其生命周期内不得更改。如果有,您需要通知容器(如果可能);否则你会得到错误的结果


编辑:如前所述,它取决于容器。显然,如果容器从不使用
hashCode
equals
方法,那么就不会出现任何问题。但一旦它尝试比较事物是否相等(所有映射和集合),您就会遇到麻烦。

哈希代码在添加到映射/集合后不得更改。在这之前对它进行更改是可以的,不过如果它不更改,通常会使类型更易于使用


如果散列代码发生更改,则不会在映射/集中找到密钥,因为即使它最终位于同一个存储桶中,也会首先更改散列代码。

当对象包含在
HashMap
/
HashSet
等中时,
hashCode()
equals()的返回值发生更改时,行为未定义(你可能会有各种奇怪的行为),所以当对象包含在这样的集合中时,你必须避免这样的键变异

人们认为最好只对键使用不可变对象(或将它们放在
HashSet
等中)。事实上,例如python不允许将可变对象用作映射中的键。在Java中允许/通常使用可变对象作为键,但在这种情况下,建议将此类对象设置为“有效不可变”.也就是说,在实例化之后,根本不改变这些对象的状态

举个例子,在映射中使用一个列表作为键通常被认为是可以的,但是您应该避免在应用程序的任何一点上修改这样的列表,以避免被讨厌的bug咬到


只要不更改
hashCode()
equals()的返回值
当对象在容器中时,你在纸上应该没问题。但是很容易错误地引入讨厌的、难以发现的bug,所以最好完全避免这种情况。

是的。很多人在这里回答了这个问题,我只是想打个比方。哈希代码类似于基于哈希的集合中的地址:


想象一下,你在一家酒店登记时叫“迈克”,然后在支票上把你的名字改为“GreatMike”。当有人找你时,你叫“迈克”,他再也找不到你了。

HashSet/HashMap中的内容更改有什么方法可以通知吗?@Jessu:没有,Java的HashSet/HashMap中没有。你需要删除对象,更改其哈希代码,然后再重新添加。哈希代码可以在对象的生命周期内更改-只是如果它已经添加到映射/集合中,你最终会被删除麻烦。可以(假设)创建一个ArrayList,向其中添加项目,然后将其用作HashMap中的键,只要以后它从未更改过。@Mehrdad:它在问题中指定(根本不是隐式的)但您的答案过于宽泛。您的答案表明,只有不可变类型才应该覆盖哈希代码。您需要更加小心地处理覆盖哈希代码的可变类型,并了解这样做的后果,但这样做是有效的,并且不会违反Javadoc中的规则。@Mehrdad@JonSkeet:实际规则是“When”在Java应用程序的执行过程中,在同一对象上多次调用hashCode方法时,如果没有修改对象上的equals比较中使用的信息,则hashCode方法必须始终返回相同的整数。'Javadoc for object.hashCode().+1表示我们讨论的是键,而不是值。值对象的哈希代码可以更改。