Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/190.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Enum.hashCode()背后的原因是什么?_Java_Enums_Hash - Fatal编程技术网

Java Enum.hashCode()背后的原因是什么?

Java Enum.hashCode()背后的原因是什么?,java,enums,hash,Java,Enums,Hash,类Enum中的方法hashCode()是final,定义为super.hashCode(),这意味着它返回一个基于实例地址的数字,该地址是程序员POV提供的随机数 将其定义为ordinal()^getClass().getName().hashCode()将在不同的JVM中具有确定性。它甚至可以更好地工作,因为最低有效位将“尽可能地改变”,例如,对于包含多达16个元素的枚举和大小为16的哈希映射,将确保没有冲突(当然,使用枚举映射更好,但有时不可能,例如,没有ConcurrentEnumMap)

类Enum中的方法hashCode()是final,定义为super.hashCode(),这意味着它返回一个基于实例地址的数字,该地址是程序员POV提供的随机数

将其定义为
ordinal()^getClass().getName().hashCode()
将在不同的JVM中具有确定性。它甚至可以更好地工作,因为最低有效位将“尽可能地改变”,例如,对于包含多达16个元素的枚举和大小为16的哈希映射,将确保没有冲突(当然,使用枚举映射更好,但有时不可能,例如,没有ConcurrentEnumMap)。按照目前的定义,你没有这样的保证,是吗

答覆摘要 使用
Object.hashCode()
与更好的hashCode比较如下:

  • 专业人士
    • 简朴
  • 反对派
    • 速度
    • 更多冲突(对于任何大小的HashMap)
    • 非决定论,传播到其他对象,使其无法用于
      • 确定性模拟
      • ETag计算
      • 查找bug,例如根据
        哈希集
        迭代顺序
我个人更喜欢更好的哈希代码,但我没有理由权重太大,也许除了速度

更新 我对它的速度很好奇,写了一篇令人惊讶的文章。对于每个类一个字段的价格,您可以使用速度快近四倍的确定性哈希代码。在每个字段中存储哈希代码会更快,尽管可以忽略不计

解释标准哈希代码速度不快的原因是,当GC移动对象时,它不能作为对象的地址

更新2
一般来说,
hashCode
的性能有些奇怪。当我理解它们时,仍然有一个悬而未决的问题,为什么
System.identityHashCode
(从对象头读取)比访问普通对象字段慢得多。

只要我们不能将enum object1发送到不同的JVM,我看不出有理由对enum(以及一般的对象)提出这样的要求


1我认为这已经足够清楚了,对象是类的实例。序列化对象是字节序列,通常存储在字节数组中。我说的是一个物体

使用Object的hashCode()并将其设置为最终版本的唯一原因是让我问这个问题。

首先,您不应该依赖这些机制在JVM之间共享对象。这根本不是一个受支持的用例。当您序列化/反序列化时,您应该依赖于您自己的比较机制,或者仅将结果与您自己的JVM中的对象进行“比较”

允许枚举
hashCode
实现为
对象
哈希代码(基于标识)的原因是,在一个JVM中,每个枚举对象只有一个实例。这足以确保这样的实现是合理和正确的

你可以这样争论:“嘿,字符串和原语的包装器(长、整数,…)都有定义良好的、确定性的
hashCode
!为什么枚举没有它呢?”首先,您可以有几个不同的字符串引用来表示同一个字符串,这意味着使用
super.hashCode
将是一个错误,因此这些类必然需要自己的hashCode实现。对于这些核心类,让它们具有定义良好的确定性哈希代码是有意义的

他们为什么选择这样解决问题?


好吧,看看。主要关注点是确保每个对象都应该返回一个不同的哈希代码(除非它等于另一个对象)。基于身份的方法非常高效,可以保证这一点,而您的建议却不能。这一要求显然比任何关于放松序列化等的“便利奖励”都要强烈。

我认为他们之所以最终确定这一要求,是为了避免开发人员通过重写一个次优(甚至不正确)的哈希代码而自食其果


关于所选择的实现:它在JVM中不稳定,但速度非常快,可以避免冲突,并且不需要在枚举中添加额外的字段。鉴于enum类的实例数通常很小,且equals方法的速度很快,如果您的算法的HashMap查找时间比当前算法的要长,我也不会感到惊讶,由于其额外的复杂性。

不要求JVM之间的哈希代码是确定性的,如果它们是确定性的,则不会获得任何优势。如果你依赖于这个事实,你就错了

由于每个枚举值只存在一个实例,
Object.hashcode()
保证永不冲突,代码重用性好,速度非常快

如果相等是由标识定义的,那么
Object.hashcode()
将始终提供最佳性能


其他哈希代码的确定性只是其实现的副作用。由于它们的相等性通常由字段值定义,因此混合非确定性值将是浪费时间

JVM强制执行对于枚举常量,内存中只存在一个对象。您不可能在单个VM中使用相同枚举常量的两个不同实例对象,也不可能使用反射,也不可能通过序列化/反序列化跨网络使用

也就是说,因为它是唯一一个表示这个常量的对象,所以它的hascode是它的地址并不重要,因为没有其他对象可以同时占用相同的地址空间。它保证是唯一的&“确定性的”(在这个意义上,在同一个VM中,在内存中,所有对象都将具有相同的引用,