为什么要使用GetHashCode()而不是Equals()?

11

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

据我所知,为了实现GetHashCode,必须对对象的字段进行一些操作。可以在这里找到一个简单的示例实现。

在我的测试中,使用1,000,000个填充了随机数据的对象对进行比较,两者的性能差不多。其中GetHashCode的实现方法是链接示例中的方式,Equals只是对所有字段调用Equals。那么为什么要使用GetHashCode而不是Equals


对于一个有许多只读字段的大型对象,可以在构造函数中计算哈希码,并将其存储为对象中的附加字段。在这种情况下,Equals方法将使用哈希码字段作为优化,然后再比较其他字段值。如果哈希码不同,则可以确定剩余字段也是不同的。无论用于哈希表还是仅用于相等性比较,都可以起到作用。GetHashCode返回预先计算的哈希码字段。如果某些字段也是不可变对象,则可以延伸到许多级并加速比较。 - Frank Hileman
这是一个好问题,点赞!这是关于 GetHashCode 主题的无数相似问题中的一个很好的变体。 - nawfal
5个回答

20
对于某些类型,进行Equals测试可能会比较昂贵。这通常需要比较类的每个字段。换句话说,它与类大小呈线性关系。较大的类比较相等的代价更高。
现在,如果您需要将一个对象与其他1000个对象进行比较怎么办?调用Equals 1000次可能会变得很昂贵。如果N是类的大小,则需要进行N*2000个字段访问。 GetHashCode生成基于类内容的“几乎唯一”的整数。换句话说,只需要访问一次类字段。一旦有了这个值,就可以将此整数与组成其他对象哈希码的1000个整数进行比较。
即使在这种简单的用例中,我们现在只需要进行N * 1000个字段访问。
但是,如果我们存储哈希码呢?当我们将对象插入哈希集时,其哈希码仅计算一次。现在,任何时候我们想要在哈希集中查找,我们只需要计算一个哈希码(外部对象的哈希码),然后只需要比较简单的整数。
因此,需要进行N个类字段访问(用于需要计算哈希码的新对象),加上一些整数比较,这些比较因算法而异,但是1)相对较少,2)便宜。

1
我没有想到存储哈希的可能性。清晰明了的解释。 - user247702
1
@Stijn:实际上,哈希表比这要复杂得多,但是基本思想是避免重新计算哈希。 - jalf
实际上,只有当所有的1001个对象都相等时,您才需要进行N * 2 * 1000个字段访问;相反,获取哈希码将_肯定_会命中每个对象中的每个字段。最终,在最坏的情况下,您将获得与字段比较相关的因素2,但会失去一些时间来获取这些哈希值。 - ubik
不要忘记,如果“Equals”很昂贵,那么它的精确等价物“GetHashCode”将同样昂贵甚至更昂贵。真正的优势在于只计算一次。好观点+1。 - nawfal

8

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


2

GetHashCode允许您将物品放入桶中-多个对象可以具有相同的哈希码。然后使用Equals在桶内查找匹配项。这使您可以快速在大型集合中查找物品。


很棒的答案 :-). 简单而且是最好的一个。 - Brillian

1

GetHashCode() 让你得到一个整数值,可以用于哈希表。这个哈希码是哈希表如此高效的原因之一。然而,可能有多个对象具有相同的哈希码。这就是为什么 Equals() 会被调用。如果这些对象不相等,则它们可以进入同一个桶中;如果它们相等,则已经在哈希表中,无需添加。


1
GetHashCode 的关键是,两个对象的哈希码不同不仅表明这两个对象不同,而且还表明了更强大的观察结果:如果一个集合中所有项的哈希码具有另一个集合中所有对象所缺少的属性,则这两个集合没有任何公共项。
例如,如果将所有 GetHashCode 返回偶数的对象放入一个集合中,将所有 GetHashCode 返回奇数的对象放入另一个集合中,然后给定一个要查找的对象,调用 GetHashCode 将使我们能够立即从其中一个集合中排除所有对象。如果使用了二十个集合,那么就可以排除十九个集合中的所有内容。如果使用 256 个集合,则可以排除 255 个集合中的所有内容。在许多情况下,根据拥有的项目数量调整集合的数量,就可以在不查看 任何 对象的情况下消除除了少数对象之外的所有对象。
查看两个对象的哈希码以确定它们是否相等很少比直接检查对象是否相等更快。另一方面,能够知道一个对象与999,990个其他对象不相等而无需查看它们,可能会比查看它们要快得多,无论平时相等性比较有多快。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接