【发布时间】:2025-12-31 03:55:07
【问题描述】:
Enum 类中的方法 hashCode() 是 final 的,定义为 super.hashCode(),表示它根据实例地址返回一个数字,是程序员 POV 的随机数。
定义它,例如因为ordinal() ^ getClass().getName().hashCode() 在不同的 JVM 中是确定性的。它甚至会更好一点,因为最低有效位会“尽可能多地改变”,例如,对于包含多达 16 个元素和大小为 16 的 HashMap 的枚举,肯定不会发生冲突(当然,使用 EnumMap 更好,但有时不可能,例如没有 ConcurrentEnumMap)。按照目前的定义,你没有这样的保证,是吗?
答案总结
使用Object.hashCode() 与上面类似的更好的hashCode 进行比较,如下所示:
- 优点
- 简单
- 对比
- 速度
- 更多冲突(对于任何大小的 HashMap)
- 不确定性,它会传播到其他对象,使其无法用于
- 确定性模拟
- ETag 计算
- 寻找错误取决于例如在
HashSet迭代顺序上
我个人更喜欢更好的 hashCode,但恕我直言,没有理由很重要,也许除了速度。
更新
我对速度很好奇,写了一个benchmark 和令人惊讶的results。对于每个类的单个字段的价格,您可以获得几乎快四倍的确定性哈希码。在每个字段中存储哈希码会更快,尽管可以忽略不计。
标准哈希码没有快多少的解释是它不能是对象的地址,因为对象被 GC 移动。
更新 2
going on 与hashCode 的性能一般有一些奇怪的东西。当我理解它们时,还有一个悬而未决的问题,为什么System.identityHashCode(从对象头读取)比访问普通对象字段慢得多。
【问题讨论】:
-
我认为默认的
hashCode()实现没有问题。而且您不应该需要它在 JVM 之间具有确定性。 -
好吧,他们已经选择了这样的字符串(以及原始包装类型)。
-
使用
Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));(在download.oracle.com/javase/6/docs/api/java/util/EnumMap.html上推荐)有什么问题吗?您将如何实施ConcurrentEnumMap? -
我认为作者的观点是,您可能会发现自己比较不同虚拟机上相同 Enum 值的两个实例,其中每个实例具有不同的内存地址,因此具有不同的 hashCode()。有些答案似乎说这不可能发生,但是那些人尝试过吗?有了 Java EE 的所有特性以及在多台主机上的部署,您能证明这不会造成问题吗?
-
Enum hashCode 和 ordinal 相同的另一个优点是在分布式环境的 ETag(HTTP 响应标头)计算中使用 Enum hashCode。(ETag 需要在所有机器上保持一致)分发,否则 ETag 会有效地失去它的缓存功能)