类Enum中的方法hashCode()是final,定义为super.hashCode(),这意味着它根据实例的地址返回一个数字,该数字是来自程序员POV的随机数.
将其定义为例如ordinal() ^ getClass().getName().hashCode()跨不同JVM的确定性.它甚至可以更好地工作,因为最低有效位会"尽可能地改变",例如,对于包含多达16个元素的枚举和大小为16的HashMap,肯定没有碰撞(当然,使用EnumMap更好,但有时不可能,例如没有ConcurrentEnumMap).根据目前的定义,你没有这样的保证,对吗?
使用Object.hashCode()比较如上所述的更好的hashCode,如下所示:
HashSet迭代顺序搜寻错误我个人更喜欢更好的hashCode,但恕我直言,没有理由权重,可能除了速度.
我对速度感到好奇并写了一个令人惊讶的结果的基准.对于每个类的单个字段的价格,您可以使用确定性哈希码,其速度快近四倍.将哈希码存储在每个字段中会更快,尽管可以忽略不计.

标准哈希码不快得多的原因是它不能成为对象的地址,因为对象被GC移动了.
一般来说,表演会有一些奇怪的事情发生hashCode.当我理解它们时,仍然存在未解决的问题,为什么System.identityHashCode(从对象标题读取)比访问普通对象字段慢.
aio*_*obe 25
使用Object的hashCode()并使其成为我可以想象的最终的唯一原因是让我问这个问题.
首先,您不应该依赖这种机制来在JVM之间共享对象.这根本不是支持的用例.序列化/反序列化时,您应该依赖自己的比较机制,或者仅将结果与您自己的JVM中的对象"比较".
让枚举hashCode实现为Objects哈希代码(基于身份)的原因是因为,在一个JVM中,每个枚举对象只有一个实例.这足以确保这种实现有意义且正确.
你可以争辩说"嘿,字符串和原语的包装(Long,Integer,...)都有明确的,确定性的,规范的hashCode!为什么枚举不具备它?" 好吧,首先,您可以使用几个不同的字符串引用来表示相同的字符串,这意味着使用super.hashCode将是一个错误,因此这些类必然需要自己的hashCode实现.对于这些核心类,让它们具有明确定义的确定性hashcode是有意义的.
他们为什么选择像这样解决它?
那么,看看实现的要求hashCode.主要关注的是确保每个对象应返回一个不同的哈希码(除非它等于另一个对象).基于身份的方法是超级有效的,并保证这一点,而你的建议没有.关于放宽序列化等方面的这一要求显然强于任何"便利奖励".
JB *_*zet 12
我认为他们最终决定的原因是避免开发人员通过重写次优(甚至不正确)的hashCode来自我攻击.
关于所选择的实现:它在JVM中不稳定,但它非常快,避免冲突,并且在枚举中不需要额外的字段.鉴于enum类的实例数量通常很少,以及equals方法的速度,如果HashMap查找时间与您的算法相比比当前更高,我不会感到惊讶,因为它具有额外的复杂性.