9:覆盖equals时总要覆盖hashcode

1.hashcode 通用约定

  • 1.在应用程序执行期间,只要对象的 equals 方法的比较嘈杂所用到的信息没有被修改,那么对这同一个对象调用多次 hashcode 方法都必须始终如一的返回同一个函数。在同一个应用程序的多次执行过过程中,每次执行所返回的整数可以不一致。

  • 2.如果两个对象根据 equals 方法的毕竟是相等的,那么调用这两个对象中任意一个对象的 hashcode 方法都必须产出同样的整数结果。

  • 3.如果两个对象根据 equals 方法比较是不相等的,那么调用这两个对象中任意一个对象的 hashcode 方法,产生的结果可以相同也可以不同。但是你应该知道,给不相等的对象产生不一样的 hash 值,有可能提高散列表的性能。

2.尽可能给不相等的对象产生不一样的 hash 值的简单方法

  • 1.把某个非零的常数值,比如17,保存在一个名为 result 的 int 类型变量中。

  • 2.对于对象中每个关键域 f(指 equals 方法中涉及的每个域),完成以下步骤:

    • a.为该域计算 int 类型的散列码c:

      1. 如果该域是 boolean 类型,计算 (f ? 1 : 0)。

      2. 如果该域是 byte、char、short 或者 int 类型,计算 (int)f。

      3. 如果该域是 long 类型,计算 (int)(f ^ (f >>> 32))。

      4. 如果该域是 float 类型,计算 Float.floatToIntBits(f)。

      5. 如果该域是 double 类型,计算 Double.doubleToLongBits(f),然后按照上面第三步,为得到的 long 类型值计算散列值。

      6. 如果该域是一个对象引用,并且该类的 equals 方法通过递归的调用 equals 的方式来比较这个域,则同样为这个域递归的调用 hashcode。如果需要更复杂d额比较,则为这个域计算一个”范式“,然后针对这个范式调用 hashcode。如果这个域的值为 null,则返回0。

      7. 如果该域s回一个数组,则要吧每一个元素当做单独的域来处理。也就是说,递归地应用上述规则。如果数组中的每个元素都很重要,可以利用 Arrays.hashCode 方法。

    • b.按照下面的公式,把 a 中计算得到的散列码 c 合并到 result 中:

      • result = 31 * result + c;
  • 3.返回 result。

  • 4.写完 hashcode 方法以后,判断一下是否满足三个条件。

在散列码计算过程中,可以把冗余域排除在外。

3.几点注意

    1. 如果一个类是不可变的,并且计算散列码的开销也比较大,就应该考虑把散列码缓存在对象内部,而不是每次请求都重新计算。
    1. 不要试图从散列码计算中排除掉一个对象的关键部分来提高性能。

results matching ""

    No results matching ""