【问题标题】:Is a GetHashCode() value unique or not for a string object?GetHashCode() 值对于字符串对象是否唯一?
【发布时间】:2012-09-10 00:13:55
【问题描述】:

谁能帮我理解,GetHashCode() 方法是如何处理字符串值的?

来自MSDN我发现:

如果两个字符串对象相等,GetHashCode 方法返回相同的值。但是,每个唯一的字符串值都没有唯一的哈希码值。不同的字符串可以返回相同的哈希码。

所以,不同的字符串可以返回相同的哈希码,哈希码对于字符串来说不是唯一的。它会导致程序核心出现错误吗?

【问题讨论】:

标签: .net string unique hashcode


【解决方案1】:

好吧,如果您的算法依赖于每个字符串都有一个唯一的哈希值,这可能会导致错误。

例如,哈希映射(.NET 中的字典)可能会因冲突而失败(即具有相同哈希但不相等的两个对象),或者它在处理冲突时不会失败,这取决于确切的实现。在这种情况下失败意味着:如果您将新对象添加到映射并且映射中已经存在与新对象具有相同哈希值的对象,那么新对象将覆盖旧对象,而不是仅仅被添加。据我所知,.NET 中的 Dictionary 类可以处理冲突。

如果您需要更具体的建议,您需要提出一个更具体的问题:您要归档什么,打算如何归档等等。

附带说明:字符串的哈希值通常不是唯一的,因为哈希值的大小是有限的,而字符串的长度则不是。可以这样想:假设哈希函数是 MD5(它不是 .Net 中的默认值),并且您有一个字符串都由十六进制字符(0-9A-Z)组成,并且字符串长度为 200 个字符:有字符串有 200^16 个可能的值,但其哈希值只有 32^16 个可能的值。

【讨论】:

  • 谢谢你,梅内。这个问题并不具体,因为我还没有真正面对过这个问题,所以这只是一个对我来说很有趣的理论问题。通常没有人关心这个问题。
【解决方案2】:

如果您假设匹配的哈希码意味着匹配的字符串,则可能会导致错误。通常,您使用哈希码将字符串分类到存储桶中,以便快速搜索和选择。如果您检测到两个字符串具有匹配的哈希码,那么您通常会比较字符串本身是否相等。

如果这不能回答你的问题,那么我不明白这个问题。

【讨论】:

  • 感谢您的回答,大卫。据我了解,需要哈希码来识别对象不同,但是既然有可能两个对象具有相同的哈希码值,这是否意味着将来可能会发生错误?
  • 这不是必需的。如果您覆盖相等函数,则最好覆盖哈希值,因为您通常期望相等的对象返回相同的哈希值。还有一些东西依赖于此,例如哈希映射(.NET 中的字典)
  • @Warlock:我不明白这个问题。具有相同哈希码的两个字符串即使它们不相同也不表示有问题。这就像两个人的首字母相同但名字不同。
  • 好的,大卫,你是对的。我相信现在一切都在正确的地方。真正的哈希码用于加速对象的搜索。我错过了这个细节,这变成了一种误解。
【解决方案3】:

所以,不同的字符串可以返回相同的哈希码,哈希码对于字符串来说不是唯一的。它会导致程序核心出现错误吗?

如果按照预期使用哈希值,则不会导致错误。 GetHashCode() 返回的哈希并不是为了提供唯一的哈希——这是不可能的,因为只有大约 40 亿个可能的哈希码(因为该方法返回一个 Int32),但可能的字符串数量是无限的。

哈希旨在提供少数个集合,而不是没有冲突。因此,您应该永远假设散列是基于值的唯一表示。您得到的唯一保证是两个不同字符串的两个不同哈希码意味着字符串不相等,因为两个相等的值应该始终产生相同的哈希。然而,两个相等的哈希码并不一定意味着两个字符串值相等。

【讨论】:

    【解决方案4】:

    Hashcode 用于加快 Hash 集合中对象的搜索速度。在内部,它们将对象存储在许多桶中。持有的对象根据其哈希码分为桶。所以当你打电话时

    var value = Dictionary["someKey"]

    字典而不是在所有内部存储桶中搜索,而是直接转到应包含该键下的值的存储桶。并且字典仅在该存储桶中搜索。

    也许这并不完全是它的实现方式,但或多或​​少应该是这样。 所以在这种情况下,字典中的不同键具有相同的哈希码并不重要。这仅意味着该键下的值将最终在同一个存储桶中。

    【讨论】:

    • 谢谢你的回答,佩里。这对于理解 .Net 中的内部流程非常有帮助。我想更深入地了解它,如果您提供文章或书籍的参考资料,我会非常兴奋:)
    【解决方案5】:

    实际上,该方法所做的保证方面的文档非常准确。哈希码遵循以下两条规则(出于可读性原因,a == b 指代a.Equals(b)#a 指代a.GetHashCode()):

    • 如果a == b 那么#a == #b
    • 如果#a != #b 那么a != b

    请注意,这不是Equals 和匹配哈希之间的等价物。如果您依赖的不止这些,那么您的代码显然存在错误。 GetHashCode 旨在将对象用作字典中的键,以便从对象快速映射到数字,但它不需要是可逆的。如果您查看字符串,您可以很容易地看到可能的字符串数量很快超过了可能的哈希码数量,因此您可以自己回答这个问题。您已经超过了 232 个可能的字符串,且字符数略多于两个字符。

    【讨论】:

      猜你喜欢
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多