如果在覆盖 Equals() 时未能覆盖 GetHashCode(),会出现啥问题? [复制]

Posted

技术标签:

【中文标题】如果在覆盖 Equals() 时未能覆盖 GetHashCode(),会出现啥问题? [复制]【英文标题】:What can go wrong if one fails to override GetHashCode() when overriding Equals()? [duplicate]如果在覆盖 Equals() 时未能覆盖 GetHashCode(),会出现什么问题? [复制] 【发布时间】:2009-03-19 00:03:18 【问题描述】:

可能重复:Why is it important to override GetHashCode when Equals method is overridden?

在 C# 中,如果在覆盖 Equals() 时未能覆盖 GetHashCode(),具体会出现什么问题?

【问题讨论】:

Jared Parsons 的博客很好地解释了实现相等性以及 GetHashCode 如此重要的原因。 Properly Implementing Equality 【参考方案1】:

最明显的方式是映射结构。

当用作字典或哈希表的键时,任何这样做的类都会有不可预知的行为。原因是该实现同时使用 GetHashCode 和 Equals 在表中正确查找值。该算法的简短版本如下

    HashCode 的模数乘以桶的数量,这就是桶的索引 为指定的 Key 和特定存储桶中的每个 Key 调用 .Equals()。 如果有匹配的值,则不匹配 = 没有值。

未能使 GetHashCode 和 Equals 保持同步将完全破坏该算法(以及许多其他算法)。

【讨论】:

实现如何确定使用多少桶?这是一个固定值吗?【参考方案2】:

将哈希/字典结构视为编号桶的集合。如果你总是把东西放在与它们的 GetHashCode() 对应的桶中,那么你只需要搜索一个桶(使用 Equals() )来查看是否有东西。如果您正在寻找正确的存储桶,这将有效。

所以规则是:如果 Equals() 表示两个对象是 Equal(),则它们必须具有相同的 GetHashCode()。

【讨论】:

与其考虑编号的桶,我认为更简单的说法是使用哈希码来避免比较。如果已知对象 X 的哈希码(无论通过何种方式)与对象 Y 的哈希码不匹配,则无需比较它们的任何其他内容。桶为代码提供了一种简单的方法来忽略哈希码不可能等于某个特定值的项目,但是许多集合明确地比较哈希码,即使是被排序到同一个桶中的项目。【参考方案3】:

如果你不覆盖GetHashCode,任何比较你的对象的东西都可能出错。

据记载,如果两个实例相等,GetHashCode 必须返回相同的值,那么任何希望测试它们是否相等的代码都有权使用 GetHashCode 作为第一次传递来分组对象可能相等(因为它知道具有不同哈希码的对象不能相等)。如果您的 GetHashCode 方法为相同的对象返回不同的值,那么它们可能会在第一遍中进入不同的组,并且永远不会使用它们的 Equals 方法进行比较。

这可能会影响任何集合类型的数据结构,但在基于哈希码的数据结构(例如字典和哈希集)中尤其成问题。

简而言之:当您覆盖Equals 时,请始终覆盖GetHashCode,并确保它们的实现是一致的。

【讨论】:

【参考方案4】:

任何使用密钥的算法都将无法工作,假设它依赖于哈希密钥的预期行为。

Equal 的两个对象应该具有相同的哈希键值,默认实现不远程保证这一点。

【讨论】:

以上是关于如果在覆盖 Equals() 时未能覆盖 GetHashCode(),会出现啥问题? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

覆盖equals时总要覆盖hashCode

24覆盖equals时请遵守通用约定

Java 对象 覆盖equals时总要覆盖hashCode

effectiveJava覆盖equals时总要覆盖hashcode

Java:Effective java学习笔记之 覆盖equals时总要覆盖hashcode

equals()和hashCode()必须同时覆盖的原因