【问题标题】:Why use GetHashCode() over Equals()?为什么使用 GetHashCode() 而不是 Equals()?
【发布时间】:2011-09-12 09:59:20
【问题描述】:

HashSet<T>.Add 首先比较GetHashCode 的结果。如果它们相等,则调用Equals

现在,我的理解是,为了实现GetHashCode某事必须对对象的字段进行。一个简单的示例实现可以在What is the best algorithm for an overridden System.Object.GetHashCode?找到。

在我对 1.000.000 对充满随机数据的对象进行比较的测试中,两者的性能大致相同。 GetHashCode 在链接示例中实现,Equals 只是在所有字段上调用 ​​Equals。那么为什么要使用GetHashCode 而不是Equals 呢?

【问题讨论】:

  • 对于具有许多只读字段的大型对象,可以在构造函数中计算哈希码并将其作为附加字段存储在对象中。在这种情况下,Equals 方法将使用哈希码字段作为优化,然后再比较其他字段值。如果哈希码不同,我们可以确定其余字段也不同。无论是在哈希表中使用,还是仅在相等比较中使用,这都有效。 GetHashCode 返回预先计算的哈希码字段。如果某些字段也是不可变对象,则可以向下扩展许多级别并加快比较速度。
  • +1 提出一个好问题。这是关于 SO 上GetHashCode 主题的无限相似问题的一个很好的变体。

标签: .net performance equals gethashcode


【解决方案1】:

对于某些类型,Equals 测试可能相对昂贵。它通常必须比较类的每个字段。换句话说,类的大小需要线性时间。比较大的类更昂贵。

现在,如果您需要将一个对象与 1000 个其他对象进行比较,该怎么办?调用Equals 1000 次可能会变得昂贵。如果 N 是类的大小,则需要进行 N*2000 字段访问

GetHashCode 会根据类的内容生成一个“几乎唯一”的整数。换句话说,类字段被访问一次。一旦你有了它,你就可以将这个整数与构成其他对象哈希码的 1000 个整数进行比较。

即使在如此幼稚的用例中,我们现在也只需要 N*1000 个字段访问。

但是如果我们存储哈希码呢?当我们将一个对象插入一个散列集时,它的散列码被计算一次。现在,任何我们想要在散列集中进行查找,我们只需要计算 一个散列码(外部对象的散列码),然后你就可以比较简单的整数。 所以 N 类字段访问(对于我们需要计算其哈希码的新对象),加上一些整数比较,这些比较取决于算法,但 1)相对较少,2)便宜。

【讨论】:

  • 我没有想到存储哈希的可能性。解释清楚。
  • @Stijn:实际上,哈希表比这复杂得多,但是,基本的想法是避免重新计算哈希
  • 其实只有1001个对象都是Equals时才需要做N*2*1000个字段访问;相反,获取哈希码肯定会命中每个对象中的每个字段。最后,在最坏的情况下,您在字段比较方面获得了 2 倍的收益,从而失去了一些时间来获取这些哈希值。
  • 不要忘记,如果Equals 很昂贵,那么它完全等价 GetHashCode 将同样或更高。当您只计算一次时,真正的优势就开始了。好点+1。
【解决方案2】:

因为如果一个算法想要测试一个对象是否已经在一组 1.000.000 个对象中,它必须调用 Equals 1.000.000 次,但 GetHashCode() 只调用一次(以及几次调用 @987654323 @ 消除具有相同哈希码但不同的对象)。

【讨论】:

    【解决方案3】:

    GetHashCode 可让您将事物放入桶中 - 多个对象可以具有相同的哈希码。然后使用 Equals 在存储桶中查找匹配项。这让您可以非常快速地找到大型集合中的内容

    【讨论】:

    • 很好的答案:-)。简单而最好的一个
    【解决方案4】:

    GetHashCode() 为您提供可用于哈希表的整数值。该哈希码是哈希表如此高效的原因之一。但是,可以有多个对象具有相同的哈希码。这就是调用Equals() 的原因。如果对象不相等,则可以进入同一个桶,如果相等,则已经在哈希表中,不需要添加。

    【讨论】:

      【解决方案5】:

      GetHashCode 的基本方面是观察到两个对象的哈希码不同不仅构成对对象不同的观察,而且是对更强大的东西的观察:如果一组中所有项目的哈希码具有另一个中所有对象所缺少的属性,则集合没有共同项。

      例如,如果将GetHashCode返回偶数的所有对象放入一个集合,将GetHashCode返回奇数的所有对象放入另一个集合,然后给定一个要查找的对象,调用GetHashCode 将允许人们立即从考虑中排除一组中的所有对象。如果不是用两套,一套用了二十套,一个人就能从十九套中消除一切。如果是 256 个集合,则可以消除 255 个。在许多情况下,如果一个人根据拥有的项目数调整集合的数量,则可以消除除少数对象之外的所有对象,而无需查看任何对象。 个。

      查看两个对象的哈希码以确定它们是否相等很少比直接检查对象是否相等更快。另一方面,能够知道一个对象不等于 999,990 个其他对象而不查看它们往往比查看对象要快得多,无论相等比较的速度有多快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-17
        • 2013-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-27
        • 2016-04-21
        • 2020-04-04
        相关资源
        最近更新 更多