【发布时间】:2009-10-04 16:43:35
【问题描述】:
Object.hashCode() 的输出是否需要在同一对象的所有 JVM 实现上都相同?
例如,如果 "test".hashCode() 在 1.4 上返回 1,它是否可能在 1.6 上返回 2。或者如果操作系统不同,或者实例之间有不同的处理器架构怎么办?
【问题讨论】:
Object.hashCode() 的输出是否需要在同一对象的所有 JVM 实现上都相同?
例如,如果 "test".hashCode() 在 1.4 上返回 1,它是否可能在 1.6 上返回 2。或者如果操作系统不同,或者实例之间有不同的处理器架构怎么办?
【问题讨论】:
没有。 hashCode 的输出可能会在 JVM 实现之间甚至在同一 JVM 上程序的不同执行之间发生变化。
但是,在您给出的具体示例中,"test".hashCode() 的值 将实际上是一致的,因为 hashCode 对 String 对象的实现是 String 的 API 的一部分(见the Javadocs for java.lang.String 和this other SO post)。
【讨论】:
来自 API
hashCode的通用合约是:
在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)
【讨论】:
不,hashCode() 的结果在单次执行期间只有不变。您不应该期望函数的结果在执行之间是相同的,更不用说在 JRE 版本或平台之间了。
【讨论】:
首先,hashCode 的结果很大程度上取决于 Object 类型及其实现。每个类包括其子类都可以定义自己的行为。您可以按照 javadoc 以及其他答案中概述的一般合同来依赖它。但该值不需要在 VM 重新启动后保持不变。特别是如果它依赖于第三方类的 .hashCode 实现。
在提到String类的具体实现时,不要依赖返回值。如果您的程序在不同的 VM 中执行,它可能会发生变化。
如果您仅提及 Sun Vm,则可以说 Sun 不会破坏现有代码(即使是编程错误)。 因此对于任何版本的 Sun VM,“test”.hashCode() 将始终准确返回 3556498。
如果您想故意在脚上开枪,请继续并依靠这一点。需要修复在“2015 Nintendo Java VM for Hairdryer”上运行的代码的人会在晚上喊出你的名字。
【讨论】:
如前所述,对于许多实现,hashCode() 的默认行为是返回对象的地址。显然,每次运行程序时,这可能会有所不同。这也与 equals() 的默认行为一致:两个对象只有当它们是同一个对象时才相等(其中 x 和 y 都是非空的,x.equals(y) 当且仅当 x == y 时) .
对于任何覆盖了 hashCode() 和 equals() 的类,通常它们是根据部分或全部成员的值以确定性方式计算的。因此,在实践中,如果一个程序运行中的对象可以说与程序另一运行中的对象相等,并且源代码相同(包括诸如 String 的源代码之类的东西) .hashCode() 如果由 hashCode() 覆盖调用),则哈希码将相同。
虽然很难想出一个合理的真实示例,但无法保证。
【讨论】:
hashCode(),并让哈希码计算包含hashCode()未被覆盖的组件对象的哈希码。
唯一的事实:应用程序运行的哈希码是相同的。再次运行可能会给出其他哈希码。
当您请求对象的哈希码时,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 可以将对象移动到另一个堆单元等。
【讨论】: