重载equals和hashCode
覆盖equals时总要覆盖hashCode,一个很常见的错误根源在没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合包括HashMap、HashSet和Hashtable。
下面是约定的内容,摘自Object规范[JavaSE6]:
1)在应用程序的执行期间,只要对象的equals方法所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
2)如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
3)如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中的任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相同的对象产生截然不同的整数结果,有可能提供散列表(hash table)的性能。
如果覆盖equals没有覆盖hashCode,将会违反上面的第2条:相等的对象必须具有相等的散列码(hashCode)。Object类里面的默认eqals方法是比较内存地址是否相等,默认的hashCode方法则是根据内存地址产生一个整数,所以Object类本身当然是符合上面规则的。当你覆盖了equals后,内存地址不同的对象可能会相等,而如果这时你没有覆盖hashCode方法的话,hashCode还是根据内存地址来生成,就会出现相等的对象具有不同的散列码的情况。
下面给出了一个重载equals和hashCode的样本:
package core;public class OverrideEqualsAndHashCodeSample { private String name; private String region; private String position; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } @Override public boolean equals(Object o) { if(o==null) return false; if(!(o instanceof OverrideEqualsAndHashCodeSample)) return false; if(this==o) return true; OverrideEqualsAndHashCodeSample o2=(OverrideEqualsAndHashCodeSample)o; if(name.equalsIgnoreCase(o2.name) && region.equalsIgnoreCase(o2.region) && position.equalsIgnoreCase(o2.position)) return true; return false; } @Override public int hashCode() { int result=17; result=31*result+name!=null?name.hashCode():0; result=31*result+region!=null?region.hashCode():0; result=31*result+position!=null?position.hashCode():0; return result; }}