重写 HashCode,什么时候这样做不会有问题?
Overriding HashCode, when would not doing so be problematic?
重写对象的等号运算符来比较字段时,也说你应该重写hashCode()。
是否会出现两个对象具有所有相同字段但不同 hashCodes() 的情况?为什么需要同时更新两者?
a.equals(b)
意味着 map.put(a, c); map.get(b)
应该产生 c
,其中 map
是 Map
、a
和 b
是键,c
是一些值。特别是,HashMap
可以非常快速地执行这些操作,但依赖于 a.hashCode()
和 b.hashCode()
才能正确执行。如果 a.hashCode() != b.hashCode()
那么它们将不会被识别为相等的键,并且使用 HashMap
的程序将以非常令人沮丧和混乱的方式出现错误行为。您应该始终假设这是一种可能性,即使您目前不打算这样做。 不要缺一不可。这也不难做到:您的 IDE 可能会为您生成它(和 equals
)。其他数据结构如HashSet
也使用它。
不重写两者的主要问题是许多容器假定这两种方法使用相同的策略。
典型情况是 HashMap,如果您重写 equals()/hashCode() 中的一个而不是两者(或不一致地重写它们),它们可能无法工作,因为它们使用 hashCode() 来查找您的存储桶键应该是,然后使用 equals() 在该桶内搜索。所以它可能最终会在错误的桶中搜索给定的键!。顺便说一句,这就是为什么有时在 get() 时找不到键,但可以通过遍历每个元素找到它的原因:迭代不使用 hadhCode()。
这与为什么你应该 永远不会 有一个 hashCode() 在对象位于 HashSet/HashMap 中时更改其值的原因类似:当你搜索您的对象,hashCode() 可能已更改并将您发送到不正确的存储桶。
重写对象的等号运算符来比较字段时,也说你应该重写hashCode()。
是否会出现两个对象具有所有相同字段但不同 hashCodes() 的情况?为什么需要同时更新两者?
a.equals(b)
意味着 map.put(a, c); map.get(b)
应该产生 c
,其中 map
是 Map
、a
和 b
是键,c
是一些值。特别是,HashMap
可以非常快速地执行这些操作,但依赖于 a.hashCode()
和 b.hashCode()
才能正确执行。如果 a.hashCode() != b.hashCode()
那么它们将不会被识别为相等的键,并且使用 HashMap
的程序将以非常令人沮丧和混乱的方式出现错误行为。您应该始终假设这是一种可能性,即使您目前不打算这样做。 不要缺一不可。这也不难做到:您的 IDE 可能会为您生成它(和 equals
)。其他数据结构如HashSet
也使用它。
不重写两者的主要问题是许多容器假定这两种方法使用相同的策略。
典型情况是 HashMap,如果您重写 equals()/hashCode() 中的一个而不是两者(或不一致地重写它们),它们可能无法工作,因为它们使用 hashCode() 来查找您的存储桶键应该是,然后使用 equals() 在该桶内搜索。所以它可能最终会在错误的桶中搜索给定的键!。顺便说一句,这就是为什么有时在 get() 时找不到键,但可以通过遍历每个元素找到它的原因:迭代不使用 hadhCode()。
这与为什么你应该 永远不会 有一个 hashCode() 在对象位于 HashSet/HashMap 中时更改其值的原因类似:当你搜索您的对象,hashCode() 可能已更改并将您发送到不正确的存储桶。