【问题标题】:Java, Object.hashCode() result constant across all JVMs/Systems?Java,Object.hashCode() 跨所有 JVM/系统的结果常量?
【发布时间】:2009-10-04 16:43:35
【问题描述】:

Object.hashCode() 的输出是否需要在同一对象的所有 JVM 实现上都相同?

例如,如果 "test".hashCode() 在 1.4 上返回 1,它是否可能在 1.6 上返回 2。或者如果操作系统不同,或者实例之间有不同的处理器架构怎么办?

【问题讨论】:

    标签: java hashcode


    【解决方案1】:

    没有。 hashCode 的输出可能会在 JVM 实现之间甚至在同一 JVM 上程序的不同执行之间发生变化

    但是,在您给出的具体示例中,"test".hashCode() 的值 实际上是一致的,因为 hashCodeString 对象的实现是 String 的 API 的一部分(见the Javadocs for java.lang.Stringthis other SO post)。

    【讨论】:

    • (虽然如果你能找到 1.0 的 JDK 会有所不同。API 文档中损坏的定义如果实现的话实际上会抛出异常。)
    • 对大多数集合也有很好的定义
    【解决方案2】:

    来自 API

    hashCode的通用合约是:

    • 只要在 Java 应用程序执行期间对同一个对象多次调用,hashCode 方法必须始终返回相同的整数,前提是没有修改对象上的 equals 比较中使用的信息。该整数不需要在应用程序的一次执行与同一应用程序的另一次执行之间保持一致。
    • 如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
    • 如果根据 equals(java.lang.Object) 方法,如果两个对象不相等,则不要求对两个对象中的每一个调用 hashCode 方法必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

    在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)

    【讨论】:

    • @finnw:是的。 hashCode 不需要为同一应用程序在同一系统上同一版本的不同运行返回相同的值,更不用说跨不同版本或不同系统或不同应用程序。
    • 身份哈希码通常存储在对象头(热点)中
    【解决方案3】:

    不,hashCode() 的结果在单次执行期间只有不变。您不应该期望函数的结果在执行之间是相同的,更不用说在 JRE 版本或平台之间了。

    【讨论】:

      【解决方案4】:

      首先,hashCode 的结果很大程度上取决于 Object 类型及其实现。每个类包括其子类都可以定义自己的行为。您可以按照 javadoc 以及其他答案中概述的一般合同来依赖它。但该值不需要在 VM 重新启动后保持不变。特别是如果它依赖于第三方类的 .hashCode 实现。

      在提到String类的具体实现时,不要依赖返回值。如果您的程序在不同的 VM 中执行,它可能会发生变化。

      如果您仅提及 Sun Vm,则可以说 Sun 不会破坏现有代码(即使是编程错误)。 因此对于任何版本的 Sun VM,“test”.hashCode() 将始终准确返回 3556498

      如果您想故意在脚上开枪,请继续并依靠这一点。需要修复在“2015 Nintendo Java VM for Hairdryer”上运行的代码的人会在晚上喊出你的名字。

      【讨论】:

        【解决方案5】:

        如前所述,对于许多实现,hashCode() 的默认行为是返回对象的地址。显然,每次运行程序时,这可能会有所不同。这也与 equals() 的默认行为一致:两个对象只有当它们是同一个对象时才相等(其中 x 和 y 都是非空的,x.equals(y) 当且仅当 x == y 时) .

        对于任何覆盖了 hashCode() 和 equals() 的类,通常它们是根据部分或全部成员的值以确定性方式计算的。因此,在实践中,如果一个程序运行中的对象可以说与程序另一运行中的对象相等,并且源代码相同(包括诸如 String 的源代码之类的东西) .hashCode() 如果由 hashCode() 覆盖调用),则哈希码将相同。

        虽然很难想出一个合理的真实示例,但无法保证。

        【讨论】:

        • @Mark:一个合理的例子是你覆盖hashCode(),并让哈希码计算包含hashCode()未被覆盖的组件对象的哈希码。
        • 这样就可以了,但是你不能让两个对象相等。两个“相等”的对象会有不同的哈希码。如果将这样的对象放入 HashMap 中,您将无法再次找到它。
        【解决方案6】:

        唯一的事实:应用程序运行的哈希码是相同的。再次运行可能会给出其他哈希码。

        当您请求对象的哈希码时,JVM 会使用其中一种 RNG 算法创建它,并将其放入对象的标头中以供将来使用。 只需查看 OpenJDK 中的 get_next_hash 函数即可。

        RNG 算法可通过 JVM arg -XX:hashCode=x 进行配置, 其中 x 是一个数字:

        0 – Park-Miller RNG(默认)

        1 - f(地址,全局)

        2 – 常数 1

        3 - 顺序计数器

        4 – 对象在堆中的地址

        5 – Xorshift(最快)

        当哈希码等于堆中的地址时 - 这有时很尴尬,因为 GC 可以将对象移动到另一个堆单元等。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-11
          • 2012-06-14
          • 1970-01-01
          • 1970-01-01
          • 2014-05-26
          • 1970-01-01
          相关资源
          最近更新 更多