如何在Java中计算枚举的哈希码,以及如何将枚举哈希代码组合在一起作为HashMap的键

2022-09-01 19:13:13

我有一个包含不同枚举(不同类型)的类。此类用作 的键。类哈希码当前实现如下:HashMap

  public static class Key implements Comparable<Key> {
    final int a;
    final Enum1 enum1;
    final Enum2 enum2;

    @Override
    public int hashCode() {
      return a ^ enum1.hashCode() ^ enum2.hashCode();
    }

    // ... definition of equals and toString ...
  }

现在,如果枚举哈希码只返回枚举定义中枚举值的索引,这将不是最佳的(冲突太多)。的方法定义是这样的:Enum.hashCode()

/**
 * Returns a hash code for this enum constant.
 *
 * @return a hash code for this enum constant.
 */
public final int hashCode() {
    return super.hashCode();
}

假设这个委托给 ,一切都应该没问题,因为对于每个枚举常量,只存在一个实例,并且在理论上类似于从对象的内部地址派生的整数。我说的对吗?Object.hashCode()Object.hashCode()

PS:当然,当在密钥中多次使用相同的枚举时,您将不得不使用更复杂的内容。


答案 1

是的,你是对的,枚举元素的哈希码将来自静态实例,绑定到内存位置,并且是唯一的。

另一方面,有更好的方法来生成具有较小碰撞概率的哈希码。例如,查看 eclipse 可以为您自动生成的默认值(右键单击、源>生成哈希代码等)

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((enum1 == null) ? 0 : enum1.hashCode());
    result = prime * result + ((enum2 == null) ? 0 : enum2.hashCode());
    return result;
}

通过将素数放入混合中(精确的数学逃脱了我),你应该更有抵抗力。

请注意,您也可以让 eclipse 为您生成一个相等的方法!(甚至是一根绳子)。不是说你必须盲目地信任他们,但他们通常是一个非常好的开始。


答案 2

如上所述,枚举在Java中是不可变的,因此为枚举生成的哈希码是哈希集合的完美键,就像字符串是完美的键一样。

枚举声明是一种特殊的类声明。枚举类型具有每个命名枚举常量的公共自类型成员。所有枚举类都具有高质量的 toString、hashCode 和 equals 方法。所有这些都是可序列化的,可比较的,并且实际上是最终的。没有一个是可克隆的。除 toString 之外的所有“对象方法”都是最终的:我们负责比较和序列化,并确保它正确完成。