解释IntelliJ默认的hashCode()实现

时间:2015-10-09 09:55:42

标签: java hashcode

我看了一下IntelliJ默认的hashCode()实现,并想知道为什么他们按照他们的方式实现它。我对哈希概念很陌生并发现了一些相互矛盾的陈述,需要澄清:

public int hashCode(){
  // creationDate is of type Date
  int result = this.creationDate != null ? this.creationDate.hashCode() : 0;
  // id is of type Long (wrapper class)
  result = 31 * result + (this.id != null ? this.id.hashCode() : 0);
  // code is of type String
  result = 31 * result + (this.code != null ? this.code.hashCode() : 0);
  // revision is of type int
  result = 31 * result + this.revision;
  return result;
}
Imo,关于这个话题的最佳来源似乎是this Java world article因为我发现他们的论点最有说服力。所以我想知道:

  1. 在其他参数中,上述源表明乘法是较慢的操作之一。那么,每当我调用引用类型的hashCode()方法时,跳过带素数的乘法不是更好吗?因为大多数时候这已经包含了这样的乘法。
  2. Java世界声明,由于未提及的原因,按位XOR ^也改善了计算:(与常规添加相比,究竟有什么优势?
  3. 当相应的类字段为null时,返回不同的值会不会更好?它会使结果更加明显,不是吗?使用非zero值是否有任何巨大的缺点?
  4. 他们的示例代码看起来更吸引我的眼球,tbh:

      public boolean hashCode() {
        return
         (name  == null ? 17 : name.hashCode()) ^ 
         (birth == null ? 31 : name.hashCode());
      }  
    

    但我不确定这是否客观真实。我也对IntelliJ有点怀疑,因为equals(Object)的默认代码比较instanceof而不是直接比较实例类。我同意Java世界文章的说法,这似乎没有正确履行合同。

1 个答案:

答案 0 :(得分:4)

对于hashCode(),我认为最小化冲突(两个具有相同hashCode()的不同对象)比hashCode()计算的速度更重要。是的,hashCode()应该很快(如果可能的话是恒定时间),但是对于使用hashCode()(map,sets等)的大型数据结构,冲突是更重要的因素。

如果你的hashCode()函数在恒定时间内执行(独立于数据和输入大小)并产生良好的散列函数(几个碰撞),渐近地,地图上的操作(get,contains,put)将在恒定时间内执行。

如果你的hashCode()函数产生大量冲突,性能将受到影响。在极端情况下,您始终可以从hashCode()返回0 - 函数本身将超级快,但地图操作将以线性时间执行(即以地图大小增长)。

在添加另一个字段的子hashCode之前乘以hashCode()通常应该提供较少的冲突 - 这是一种基于通常字段包含相似数据/小数字的启发式方法。

考虑一个Person类的例子:

class Person {
    int age;
    int heightCm;
    int weightKg;
}

如果你只是将数字加在一起来计算hashCode,那么对于所有人来说,结果将在60到500之间。如果你按照Idea的方式乘以它,你将获得2000到100000之间的hashCodes - 更大的空间,因此更低的碰撞机会。

使用XOR不是一个好主意,例如,如果您的字段Rectangle包含字段heightwidth,则所有正方形都具有相同的hashCode - 0

对于使用equals()instanceof的{​​{1}},我从未见过有关此问题的结论性辩论。两者都有其优点和缺点,如果你不小心,这两种方式都会引起麻烦:

  • 如果您使用getClass().equals(),则覆盖instanceof的任何子类都可能会破坏对称性要求
  • 如果你使用equals(),这对于像Hibernate这样生成自己的类子类来存储自己的技术信息的框架来说效果不佳