我目前正在阅读Troelsen的书籍C#和.NET 4.5框架。书中有一节他有一个覆盖的例子
public virtual int GetHashCode(); // Defined in System.Object
他说(以下引用来自Troelsen的书):
鉴于String类已经具有使用字符数据的实体哈希码算法 用于计算哈希值的字符串,如果您可以在类上标识一个对于所有实例(例如社会保险号)应该是唯一的字段数据,则只需在该点上调用GetHashCode() 现场数据。
基本上他说的是某个类有一个成员(自动只读属性)
public string SSN {get; }
该类的每个实例都将具有唯一的字符串值。 现在,在的假设下
// s1 and s2 are strings
s1.GetHashCode() != s2.GetHashCode(); // Assumption: If this true then s1 == s2 is true
他的推理是有效的。但是,当我读到String.GetHashCode()时:
如果两个字符串对象相等,则GetHashCode方法返回相同的值。但是,每个唯一字符串值都没有唯一的哈希码值。 不同的字符串可以返回相同的哈希码。
我想你知道我要去哪里。我想是我错过了什么,如果有的话,请指出我正确的方向。
谢谢!
答案 0 :(得分:5)
你是对的,相同的哈希码不能保证相等的值。
你认为这句话的含义是错误的。
此引用特别针对实现包含Person
属性的SSN
类的哈希码计算的上下文。等于SSN
值表示相等的Person
值。不同的SSN
值表示不同的Person
值。 (注意:实际上这不一定是真的。)
现在,您需要对Person
进行哈希码计算,以确保两个相等的Person
实例具有相同的哈希码,理想情况下,这可能导致两个不等Person
个实例一个不同的哈希码,虽然后者永远无法保证。由于相等性是根据SSN定义的,这意味着重新使用SSN的哈希码已经实现了这一点。
答案 1 :(得分:5)
如果两个字符串对象相等,则GetHashCode方法返回相同的值。但是,每个唯一字符串值都没有唯一的哈希码值。不同的字符串可以返回相同的哈希码。
有无数个字符串,但只有2 ^ 32个可能的哈希码值。两个不同的字符串最终将具有相同的散列值是不可避免的。由于birthday problem,这种情况比人们想象的更频繁。
不要用作唯一标识符
这是一个很好的建议。 .NET的调试版本实际上会定期更改哈希代码以帮助捕获此类问题,并且不同的框架版本无法保证生成相同的哈希。更多see this。
看看Eric Lippert的blog on the topic。
答案 2 :(得分:3)
GetHashCode
的目的不是为对象生成唯一标识符,而是为了实现基于hash tables的数据结构,例如Dictionary<K, V>
或HashSet<T>
哈希函数必需以确保x == y
,然后x.GetHashCode() == y.GetHashCode()
,但反之为不为真:两个不同的对象可以具有相同的哈希码。这种情况称为哈希冲突。
如果存在冲突,哈希表结构仍将工作,但它们运行速度较慢,因为您的程序必须花时间消除 冲突对象的哪个寻找。因此,良好的哈希函数将努力减少冲突。 (注意,由于pigeonhole principle,如果一个类有超过2个 32 可能的值,那么完全避免冲突的数学上是不可能的。 )
那么,你如何为你的班级写一个好的GetHashCode
实现呢?做一些复杂的数学运算将每个类的字段转换为int
,然后对其进行分析以确定其中系数的最佳值?
据Troelsen说,没有。只需使用“最独特”的string
字段,然后点击GetHashCode()
即可。编写System.String.GetHashCode
的开发人员知道他们在做什么,所以只需使用它,您就会自动利用他们的“实体哈希码算法”。