String.hashCode()是否可以跨VM,JDK和OS移植?

时间:2008-10-10 07:11:00

标签: java hashcode

最近出现了一个有趣的问题。我们遇到了一些使用hashCode()作为MD5加密的salt源的代码但是这提出了一个问题:将hashCode()返回不同VM,不同JDK版本和操作系统上相同对象的相同值?即使它没有保证,它现在在任何时候都有变化吗?

编辑:我的意思是String.hashCode(),而不是更普遍的Object.hashCode(),当然可以覆盖它。

5 个答案:

答案 0 :(得分:8)

没有。来自http://tecfa.unige.ch/guides/java/langspec-1.0/javalang.doc1.html

  

hashCode的一般契约是   如下:

     
      
  • 每当在同一个对象上多次调用它时   执行Java应用程序,   hashCode必须始终返回   相同的整数。整数可以是   正面,负面或零。这个   但是,整数不是必须的   从一个Java保持一致   申请到另一个,或从一个   执行应用程序到另一个   执行相同的应用程序。   [...]
  •   

答案 1 :(得分:3)

取决于类型:

  • 如果你有一个没有覆盖hashCode()的类型,那么每次你运行程序时它可能会返回一个不同的hashCode()。
  • 如果你有一个覆盖hashCode()的类型,但没有记录它是如何计算的,那么具有相同数据的对象在每次运行时返回不同的哈希是完全合法的,只要它返回相同的在同一次运行中重复调用的哈希值。
  • 如果你有一个以记录的方式覆盖hashCode()的类型,即算法是记录行为的一部分,那么你可能是安全的。 (例如,java.lang.String记录了这一点。)但是,我个人仍然会在一般原则上避开依赖

来自.NET世界的一个警示故事:通过使用string.GetHashCode()的结果作为数据库中的密码哈希,我看到至少有一些人处于痛苦的世界。算法在.NET 1.1和2.0之间发生了变化,突然所有的哈希都是“错误的”。 (Jeffrey Richter通过C#记录了CLR中几乎完全相同的情况。)当需要存储哈希 时,我宁愿以总是的方式计算它>保证稳定 - 例如MD5或您的类型实现的自定义界面,保证稳定性。

答案 2 :(得分:2)

根据docs:String对象的哈希码计算为

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

我不确定这是正式规范还是Sun的实施。至少,它应该在所有现有的Sun VM上都是相同的,无论平台或操作系统如何。

答案 3 :(得分:1)

没有。除非另有说明,否则无法保证散列算法。因此,例如,哈希结构的反序列化需要重新计算哈希码,并且这些值不应以序列化形式存储。

答案 4 :(得分:0)

我想补充一点,您可以覆盖hashCode()(如果这样做,请不要忘记equals())以确保您的业务对象在任何地方返回相同的hashCode。那些对象至少会有一个可预测的hashCode。