注意 .NET string.GetHashCode() 用法
需求案例:需要把字符串存入数据库,并且要求数据库中不能有重复的字符串,由此就引出了将字符串hash成特定的hash值,依靠查询hash值是否重复来判断字符串是否重复。这样做的好处在于查询重复字符串的代价太大,因为字符串可能会非常长,进行逐个比较非常消耗数据库的性能,如果将字符串hash之后,依靠hash值来查重就显得轻便很多了,因为hash值通常都比字符串本身短很多。由于使用的是C#,自然而然就用了string的GetHashCode函数,MSDN上说该函数得到的返回值可以唯一区别一个string,意思就是相同的字符串肯定会得到相同的hash值,不同的字符串的hash值肯定不一样。当时还在疑惑,这个函数的返回值是int型,算起来也就几十亿,但是字符串的组合却是无穷的啊,微软是怎么实现唯一性的呢?
测试结果:调试代码发现用hash值查询一个数据库中已经存在的string,居然说没有重复!这就相当让人费解了,string已经存在了,那么其hash值也肯定已经存在在数据库中,怎么会说没有重复呢?仔细debug代码,惊讶的发现原来string的hash值居然变了,变成了一个和数据库中完全不同的值。
那么为什么同一个string,两次运行GetHashCode得到的返回值却不一样呢?
原来GetHashCode只是保证在同一个进程的内存空间中,string的返回值可以唯一区别一个string。在同一个进程的内存空间中,每个string的hash值都被微软保证不会重复(除非两个string的内容一样),虽然字符串的组合是无限的,但是对于一个进程的内存空间,顶多就几个G的,几个G的内存所能容纳的string的组合就变成了“有限的”了,int型的几十亿足够来保证这些“有限的”string组合有不同的hash值。
但是微软不保证同一个string在调用GetHashCode之后得到的返回值是相同的!因为int就几十亿,如果用来保证每次调用得到的返回值相同,那么势必出现hash值的碰撞。
这也是为什么MD5,SHA2等hash算法得到的返回值都是128位或者256位的原因,因为只有足够长,才能保证少发生碰撞或者发生碰撞之后可以二次hash。
PS:看看微软对这个函数的备注
http://msdn.microsoft.com/zh-cn/library/system.string.gethashcode.aspx
备注
GetHashCode 的行为取决于它的实现,此实现可能会从一个公共语言运行时版本更改为另一个版本。 原因可能是为了提高 GetHashCode 的性能。
说明说明
如果两个字符串对象相等,则 GetHashCode 方法返回相同的值。 但是,每个唯一的字符串值并没有唯一的哈希代码值。 不同的字符串可以返回相同的哈希代码。
有关哈希代码的更多信息,请参见 Object.GetHashCode。