【问题标题】:Is hashcode() a good way to compute an unique token from a list of informations?hashcode() 是从信息列表中计算唯一令牌的好方法吗?
【发布时间】:2014-07-23 15:36:55
【问题描述】:

我有一个

HashMap<String,AnObject> 

我想从 AnObject 值包含的一些信息中为字符串键提供一个值。 假设 AnObject 是这样制作的:

public class AnObject(){
     public String name;
     public String surname;
}

将密钥分配给:

String.valueOf(o.name.hashcode()+o.surname.hashcode());

?或者有没有更好的方法从值列表中计算字符串哈希码?

【问题讨论】:

  • 如果用于构造键的字段始终是唯一的,那么您就可以了。
  • @Kyte:这根本不是真的。如果您真的希望我可以找到具有相同哈希码的不同字符串的示例...
  • @Kyte 他们很容易故意找到。只需散列 2^32 个字符串。在现代计算机上散列 2^32 个短字符串最多需要一个小时,而且可能要少得多(即分钟)
  • @Kyte:“稀有”和“从不”不是一回事。哈希码根本不是一个合适的键,您声称不同的字符串导致不同的哈希是不正确的。我们不知道该密钥将用于什么 - 想象一下这是否是一种查找私人信息的方式;使用哈希很容易成为一个非常重要的安全漏洞。
  • @Kyte,字符串“FB”和“Ea”具有相同的哈希码,而且还有很多类似的。

标签: java


【解决方案1】:

不,绝对不是。 hashCode()保证是唯一的。

哈希码的规则很简单:

  • 两个相等的值必须具有相同的哈希码
  • 两个不相等的值理想情况下会有不同的哈希码,但可以有相同的哈希码。特别是,只有 232 个可能的值可以从 hashCode() 返回,但超过 232 个可能的字符串,使得唯一性是不可能的。
  • 除非对象的某些对等式敏感的方面发生更改,否则对象的哈希码不应更改。确实,通常让实现值相等的类型不可变是一个好主意,至少在平等敏感方面是这样。否则,您很容易发现无法使用与之前用于键的完全相同的对象引用来查找条目!

哈希码是一种优化技术,可以快速找到一组“可能很小”的 candidate 值等于某个目标,然后通过严格的相等性检查对其进行迭代以查找是否存在其中实际上等于目标。这就是让您在基于散列的集合中快速通过键查找内容的原因。关键不是哈希本身。

如果您需要从两个字符串创建一个键,您基本上必须 from 这两个字符串(使用某种分隔符,以便您可以区分 {" a", "bc"} 和 {"ab", "c"} - 如果您不小心,分隔符本身可能会出现在值中)。

更多信息请见Eric Lippert's blog post on the topic;这是基于 .NET 而不是 Java,但它们都适用。同样值得理解的是hashCode 的语义不一定与加密哈希的语义相同。特别是,如果您启动一个新的 JVM 但创建一个具有相同字段的对象,hashCode() 的结果会发生变化 - 没有人应该坚持 hashCode 的结果。 SHA-256 之类的东西不是这种情况,它对于特定的数据集应该是永久稳定的。

【讨论】:

  • 哈希码均为 0 的字符串示例:stackoverflow.com/questions/2310498/…
  • 另外一个(虽然非常重要的规则):哈希值应该是稳定的。程序员经常从每个内部字段计算散列,这可能会导致问题(使用对象作为散列映射中的键,然后更改不重要的字段,之后不再在散列映射中找到该对象)。明智地选择用于计算哈希的字段(最终字段是最佳选择)。
  • @PeterWalser:它应该在特定的上下文中保持稳定。它不需要在流程执行等之间保持稳定。特别是,您不应该存储 hashCode 的结果。将在答案中编辑一些内容。
【解决方案2】:

String 的哈希码是有损的;许多字符串值将产生相同的哈希码。一个整数有 32 位位置,每个位置有两个值。甚至没有办法将 32 个字符的字符串(例如)(每个字符都有很多可能性)映射到 32 位而不发生冲突。他们就是不适合。

如果您想使用任意精度的算术(例如 BigInteger),那么您可以将每个字符作为一个整数并将它们连接在一起。

【讨论】:

    【解决方案3】:

    不,hashCode()(顺便说一句,注意字母C 的大小写)不保证唯一性。您可以拥有许多产生相同哈希码的对象。

    如果您需要唯一标识符,请使用 java.util.UUID 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多