equals()和hashCode()方法是Java类库大多都继承和实现的方法。前者用于比较对象之间内容相等性,后者用于对象在HashMap中提供有效的索引。那么,在软件设计中该如何override这两个方法呢?
对象相等性
对象在创建后有两个标识equals和hashCode。通常情况下,如果重写了其中一个方法,也必须重写另一个方法。即要求equals相等的对象,要求其hashCode值也相等。
如果在Class中不 Override equals()和hashCode()。如果从未在HashMap或其它基于散列的集合中使用该类作为关键字的话,什么也不会发生。但是,如果在HashMap中使用该类实体对象作为关键字,我们将不能够可靠地检索到相关值,除非我们在get()调用中使用与put()调用中极其类似的类实例,这种方法极不方便而且出错的概率也非常大。
其实,程序也可根据equals()方法识别具体的类,但是由于equals()方法在计算方面非常耗时。Java平台设计人员为满足应用程序中基于散列的集合类(Collection Class)--如Hashtable,HashMap 和HashSet,创造出hashCode并结合使用基于散列的集合,提高存储和检索的效率。
重新equals和hashCode原则
在重新equals()和hashCode()原则有:
- Symmetry:两个引用, a和b a.equals(b)则有b.equals(a)。
- Reflexivity:所有非空引用,a.equals(a)。
- Transitivity:如果a.equals(b) 且b.equals(c), 则a.equals(c。
- Consistency with hashCode() :两个相等的对象必须有相同的hashCode()值。
- Non nullity:非空性,任何飞空的对象a,a.equals(null)返回为false。
编写有效的equals和hashCode方法
如何编写有效的equals和hashCode方法是类设计的关键。equals方法相对简单,这里不做介绍。不理想的hashCode方法会导致不相等的类具有相同的hashCode值,这将给散列集合类查找带来错误的结果。比如类:
class Example{
int a;
int b;
}
糟糕的hashCode:
public int hashCode() {
return a + b;
}
如何才能设计良好的hashCode实现呢?良好的hashCode实现即要保存某一个变量的特性,还要保存其他变量的特性。
class A {
final B someNonNullField;
C someOtherField;
int someNonStateField;
}
好的hashCode实现,保存了3个属性值得特性:
public int hashCode() {
int hash = 1;
hash = hash * 31 + someNonNullField.hashCode();
hash = hash * 31
+ (someOtherField == null ? 0 : someOtherField.hashCode());
return hash;
}
总结
equals()
和 hashCode(),
提升类在散列集合应用中的可行性。但是,当对象状态发生变化导致对象散列值发生变化时,有可能取到错误的结果。