覆盖 equals 方法时应同时覆盖 hashCode 。(java)

很多时候,会有覆盖 equals 的时候。此类需求多出现在使用领域对象的时候。项目里曾经做过多次。有时候是为了功能,有的时候是为了使用方便。

虽然很多时候开发者可以在需要判断使用自己的防范对对象值进行判断。但是另外一些时候这么做非常不方便。

在 List 的中间保存数据的时候,有时需要将放入 List 的数据 remove ,或者查找指定对象在 List 里的位置,此时Collections 里的实现会调用 equals 方法判断两个对象是否相同。

当自己覆盖了 equals 的时候,有时候是出于缺乏经验,有时是偷懒,没有同时覆盖 hashCode 方法。


按照 java api 中 hashCode() 的定义,是需要同时实现这两个方法的。
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#hashCode()

摘自java.lang.Object规范:

l         在同应用程序执行期间,对同一个对象调用hashCode(),必须传回相同的整数结果前提是equals()所比较的信息都不曾被改动过。至于同一个应用程序在不同执行期所得的呼叫结果,无需一致。

l         如果两个对象被equals(Object)函数视为相等,那么对这两个对象调用hashCode()必须获得相同的整数结果。

l         如果两个对象被equals(Object)函式视为不相等,那么对这两个对象调用hashCode()不必产生不同的整数结果。然而程序员应该意识到,对不同对象产生不同的整数结果,有可能提升hash table 的效率。


生成 hash code 的算法。

最简单的:

public int hashCode(){
  return 42;
}

法的,因为保证的对象具有相hash 。但也是的,因为它使每个对有相hash ,这会成每个对都被hashing hash bucket使hash tables linked lists:如果考虑rehashing,还是能来)。只需线执行,如需要执行,这对大hash table而言会影响程序的实用性。

稍微复杂一点的实现:

1. 将一个非0常数,例如17,储存于int result变量㆗。
2. 对对象中的每㆒个有意义的字段f(更确切㆞说是被equals()所考虑的每一个字段)进行如㆘处理:
 A. 对这个字段计算出型别为int的hash 码 c:
  i. 如果字段是个boolean,计算(f ? 0 : 1)。
  ii. 如果字段是个byte,char,short或int,计算(int)f。
  iii. 如果字段是个long,计算(int)(f^(f >>> 32))。
  iv. 如果字段是个float,计算Float.floatToIntBits(f)。
  v. 如果字段是个double,计算Double.doubleToLongBits(f),然后将计算结果按步骤2.A.iii处理。
  vi. 如果字段是个object reference,而且class 的equals()透过「递归呼叫equals()」的方式来比较这一字段,那么就同样也对该字段递归呼叫hashCode()。如果需要更复杂的比较,请对该字段运算㆒个标准表述式(canonical representation),并对该标准表述式呼叫hashCode()。如果字段值是null,就传回0(或其它常数;传回0 是传统做法)。
  vii. 如果字段是个array,请将每个元素视为独立字段。也就是说对每一个有意义的元素施行上述规则,用以计算出hash 码,然后再依步骤2.B将这些数值组合起来。
 B. 将步骤A计算出来的hash码 c按下列公式组合到变量result中:result = 37*result + c;
3. 传回result。
4. 完成hashCode()之后,反躬自省一下:是否相等的实体具有相等的hash 码?如果不是,找出原因并修正问题。

public int hashCode() {
 int result = 17;
 result = 37*result + areaCode;
 result = 37*result + exchange;
 result = 37*result + extension;
 return result;
}

-- 摘自《effective java programming language guide》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值