第三章:对于所有对象都通用的方法。ITEM9:覆盖equals时总要覆盖hashCode。

1.在应用程序执行期间,只要对象的 equals 方法的比较操作所用到的信息没有被修改,那么对这同一个对象多次调用,hashCode 方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执
行过程中,每次执行所返回的整数可以不一致。
2.如果两个对象根据 equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的 hashCode 方法都必须产生同样的整数结果。
3.如果两个对象根据 equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的 hashCode 方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然
不同的整数结果,有可能提高散列表的性能。如果类没有覆盖 hashCode 方法,那么 Object 中缺省的 hashCode 实现是基于对象地址的,就像equals 在 Object 中的缺省实现一样。如果我们覆盖了equals 方法,

那么对象之间的相等性比较将会产生新的逻辑,而此逻辑也应该同样适用于 hashCode 中散列码的计算,既参与 equals 比较的域字段也同样要参与 hashCode 散列码的计算。

 1 package com.twoslow.cha3;
 2 
 3 public final class PhoneNumber {
 4 
 5     private final short areaCode;
 6     private final short prefix;
 7     private final short lineNumber;
 8 
 9     public PhoneNumber(int areaCode, int prefix, int lineNumber) {
10         this.areaCode = (short) areaCode;
11         this.prefix = (short) prefix;
12         this.lineNumber = (short) lineNumber;
13     }
14 
15     @Override
16     public boolean equals(Object o) {
17         if(o == this)
18             return true ;
19         
20         if(!(o instanceof PhoneNumber))
21             return false ;
22         
23         PhoneNumber pn = (PhoneNumber) o ;
24         return pn.areaCode == areaCode 
25                 && pn.prefix == prefix && pn.lineNumber == lineNumber ; 
26     }
27     
28     
29     /*
30      * 如果不覆盖hashCode,导致两个相等的实例具有不相等的散列码。
31      */
32     @Override
33     public int hashCode() {
34         int result = 17;
35         result = 31 * result + areaCode;
36         result = 31 * result + prefix;
37         result = 31 * result + lineNumber;
38         return result;
39     }
40 }
1 Map<PhoneNumber, String> map = new HashMap<PhoneNumber, String>() ;
2         
3         PhoneNumber pn1 = new PhoneNumber(1, 2, 3) ;
4         map.put(pn1, "cjh") ;
5         PhoneNumber pn2 = new PhoneNumber(1, 2, 3) ;
6         //如果不覆盖hashCode,map.get(pn2)为null
7         System.out.println(map.get(pn2));

覆盖hashCode的一个简单的解决办法:

  1.final int result = 17 ;或者某个非0的常数。

  2.为该域计算int类型的散列吗c:

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

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

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

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

    e.如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤c,为得到的long类型值计算散列值。

    f.如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals的方式来比较这个域,则同样为这个域递归地调用hashCode。

    h.如果该域是一个数组,则要把每一个元素当做单独的域来处理。如果每个元素都很重要,可以使用Arrays.hashCode()方法。

  3.按照下面的公式,把步骤2中计算得到的散列码c合并到result中:result = 31 * result + c ;

  4.返回result。

  5.验证是否正确。

转载于:https://my.oschina.net/u/726229/blog/310082

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值