Effective Java (9) 覆盖equals时总要覆盖hashCode

来源:互联网 发布:淘宝店铺怎么交保证金 编辑:程序博客网 时间:2024/06/06 05:15

这个是一直强调的了。

java规范中Object规范要求同一对象的hashCode多次调用保持不变,对象相等则hashCode必须相等,反之对象不相等,hashCode不必不相等,只是不相等的hashCode会改善散列表的性能。

所以在覆盖equals时,一定要将hashCode一起覆盖。否则极易出现,对象放入HashMap等hash集合后,再去除便取不着的情况。比如

public class PhoneNumber{   private final short areaCode;   private final short prefix;   private final short lineNumber;   public PhoneNumber(int areaCode, int prefix, int lineNumber){    //...set values   }   @Override public boolean equals(Object o){    if(o==this) return true;    if(! (o instanceof PhoneNumber)) return false;    PhoneNumber pn = (PhoneNumber)o;    return pn.lineNumber ==lineNumber && pn.prefix == prefix && pn.areaCode==areaCode;   }   //No hashCode() overrided!}

则这时:

Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();m.put(new PhoneNumber(707,867,5309),"Jenny");

这是如果调用

m.get(new PhoneNumber(707,867,5309));
返回的对象会使null。因为hashCode对于put和get方法中的PhoneNumber是不一样的。所以HashMap将第一个对象存入了一个散列桶,而用另一个对象的hashCode从另一个桶中取对象。及时巧合般的2个对象被分在同一个桶中,也会因为hashCode的不同,直接在对象相等验证中失败。

同时,hashCode总是返回同一个或极少量的值也是不行的。因为这样会使一个以hashCode会key的多桶的数据结构退化,成为一个只有一个hashCode的超大的桶,既一个链表。这样这个数据结构的查询效能就冲Log(O)退化为(O)2,这对于一些大的hash集合而言,是影响性能甚至会导致程序不可用的。

书中介绍了一些hashCode生成的范式。也没有太明白,貌似hashCode的实现不仅仅是一个工程学问题,更是一个数学问题,水可以很深。本人道是经常使用apache的HashCodeBuilder来完成hashCode的生成:

@Overridepublic int hashCode() {   return new HashCodeBuilder(13, 31).append(this.id) .append(this.fieldA).append(this.fieldB).toHashCode();  }  
方便又好用。


0 0
原创粉丝点击