第九条:覆盖equals方法时总要覆盖hashCode方法

时间:2021-08-14 18:08:04

Object类的hashCode方法:

public native int hashCode();   是一个本地方法。

其中这个方法的主要注释如下:

Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method
must consistently return the same integer, provided no information used in equals comparisons on the object is modified.

在一次应用程序执行期间,只要对象的equals方法没有改变,那么对于同一个对象无论调用多少次hashCode方法,都应该返回同一个整数。
This integer need not remain consistent from one execution of an application to another execution of the same application.

在应用程序的多次执行时,调用hashCode方法,每次执行的返回整数可以不一样 。

If two objects are equal according to the equals(Object)  method, then calling the hashCode method on each of  the two objects must produce the same integer result.

如果两个对象根据equals方法返回的结果是true,即这两个对象是逻辑相等的,那么这两个对象的hashCode方法应该返回同一个整数。

It is not required that if two objects are unequal  according to the {@link java.lang.Object#equals(java.lang.Object)}  method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

如果两个对象根据equals方法返回的结果是false,即这两个对象不是逻辑相等的,那么这两个对象的hashCode方法可以返回同一个整数,也可以返回不同的整数,

但是,程序员应该认识到对于逻辑不相等的两个对象,它们的hashCode方法返回不同的整数,有可能提高散列表的性能。

在每个覆盖了equals方法的类中,必须覆盖hashCode方法,那么就会违反上面的hashCode的通用约定,这样导致该类无法结合所有基于散列的集合一起正常工作,

这样的集合包括HashMap,HashSet,Hashtable。

Object类的hashCode方法 ,为每个不同的实例对象返回不同的整数,如果我们覆盖了equals方法,而继承了hashCode方法,那么就算是两个逻辑相等的对象,对于hashCode方法来说,也是两个不同的实例对象,也返回的是不同的整数。

如何写一个好的hashCode方法:

自定义散列函数 ,产生的散列值,使得逻辑相同的对象有相同的散列值(放入同一个桶中),逻辑不同的对象有不同的散列值(放入不同的桶中)。

结合equals方法的关键域,有如下步骤:

1.把一个非零的常数值,如17,保存在一个名叫result的int变量中;

2.对于equals方法中的关键域产生int类型散列值:

boolean类型的域(如名叫f)      计算(f?1:0)

byte,char,short,int类型的域      计算 (int)f

long类型的域                          计算 (int)(f^(f>>>32))

float类型的域                          计算 Float.floatToIntBits(f)

double类型的域                       计算  Double.doubleToLongBits(f)

引用类型的域                           使用 引用类型的hashCode方法得到的散列值

数组类型的域                           把数组中的每个元素当成一个关键域,计算出散列值。

3.对于每一个关键域计算出来的散列值 (如名叫c)

result = result * 31 + c;

最后放回这个result整数   就是计算出来的当前调用hashCode方法得到的散列值。

注意不要试图从散列值的计算过程中排除一个关键域来提高散列值计算的性能。

关于散列表:

第九条:覆盖equals方法时总要覆盖hashCode方法

第九条:覆盖equals方法时总要覆盖hashCode方法

相同散列值的对象被放入同一个桶中,这样寻找一个对象时,先算出这个对象的散列值,就知道到哪个桶中去找这个对象了 ,提高了查找性能。