Enum 类中的 hashCode() 方法是最终方法,定义为 super.hashCode(),这意味着它返回一个基于实例地址的数字,该数字是来自程序员 POV 的随机数。
定义它例如作为ordinal() ^ getClass().getName().hashCode()
在不同的 JVM 上是确定性的。它甚至会工作得更好一点,因为最低有效位将“尽可能多地改变”,例如,对于包含最多 16 个元素的枚举和大小为 16 的 HashMap,肯定不会发生冲突(当然,使用 EnumMap 更好,但有时不可能,例如没有 ConcurrentEnumMap)。根据当前的定义,你没有这样的保证,不是吗?
答案摘要
Using Object.hashCode()
与上面的更好的 hashCode 相比,如下所示:
- PROS
- CONTRAS
- speed
- 更多碰撞(对于任何大小的 HashMap)
- non-determinism, which propagates to other objects making them unusable for
- 确定性模拟
- ETag计算
- 追捕错误取决于例如在一个
HashSet
迭代顺序
我个人更喜欢更好的 hashCode,但恕我直言,没有任何理由很重要,也许除了速度之外。
UPDATE
我对速度感到好奇并写了一篇基准 https://dl.dropboxusercontent.com/u/4971686/published/maaartin/so/EnumHashCodeBenchmark.java与令人惊讶的results https://microbenchmarks.appspot.com/runs/6af10de0-e379-4aad-a354-cbc8815a466c。对于每个类单个字段的价格,您可以得到一个确定性哈希码,该码几乎是快四倍。将哈希码存储在每个字段中会更快,尽管可以忽略不计。
标准哈希码速度并不快的原因是,当对象被 GC 移动时,它不可能是对象的地址。
UPDATE 2
有一些奇怪的事情going on https://stackoverflow.com/q/24222991与hashCode
表现一般。当我理解它们时,仍然有一个悬而未决的问题,为什么System.identityHashCode
(从对象头读取)比访问普通对象字段慢得多。
我可以想象,使用 Object 的 hashCode() 并将其最终确定的唯一原因是让我问这个问题。
首先,您不应该依赖这种机制在 JVM 之间共享对象。这根本不是受支持的用例。当您序列化/反序列化时,您应该依赖您自己的比较机制,或者仅将结果与您自己的 JVM 中的对象进行“比较”。
让枚举的原因hashCode
实施为Objects
哈希码(基于身份)是因为,在一个 JVM 内,将会有只能是每个枚举对象的一个实例。这足以确保这种实现是有意义且正确的。
你可以像这样争论“嘿,字符串和原语的包装器(长整型、整数……)都有明确定义的、确定性的规范hashCode
!为什么枚举没有它?”,首先,您可以有几个不同的字符串引用来表示同一个字符串,这意味着使用super.hashCode
将会是一个错误,因此这些类必须需要它们自己的 hashCode 实现。对于这些核心类,让它们具有明确定义的确定性哈希代码是有意义的。
Why他们选择这样解决吗?
嗯,看看的要求hashCode执行 http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode%28%29。主要关心的是确保每个对象都应该返回一个distinct哈希码(除非它等于另一个对象)。基于身份的方法非常有效并保证了这一点,而您的建议却没有。这一要求显然比任何关于放松连载等的“便利奖金”都要强。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)