前言
感觉自己在课上听得重写equals和hashCode方法有点云里雾里,所以自己学习梳理了一遍,现总结如下:
一、equals方法
1、为什么要重写equals方法?
equals方法是判断两个对象是否相等的方法,那么为什么要重写equals方法呢?首先我们来看一下Object关于equals()的源码:
public boolean equals(Object obj) {
return (this == obj);
}
从源码中可以看到,equals()方法是利用==来比较两个对象是否相等的,也就是说他是通过比较两个对象的地址是否相同来判断他们是否相等。
可实际情况中,也有两个对象地址不同但我们认为他们是同一对象的情况。例如,一个People类,有两个属性,姓名和身份证号。我们判断两个对象相等的标准是这两个对象的身份证号相等。但如果我们new两个People对象,使这两个People对象的身份证号相同(注意,由于这两个对象是new出来的,所以他们的地址肯定是不同的)。在我们的判断标准下,这两个对象是同一个对象,但如果不重写equals(),调用equals()的返回值一定是false。这就出现了矛盾,因此很多实际情况中是需要重写equals()方法的。
public class People {
private String name;
private String number;
}
2、如何重写equals方法?
我们以上面这个简单的例子为例
@Override
public boolean equals(Object obj) {
if(!(obj instanceof People)) {//obj为空的情况
return false;
}
People PeoObj = (People) obj;
if (this == PeoObj) {//相同地址一定是同一对象
return true;
}
if (PeoObj.number.equals(this.name)) {//相同的身份证号是同一对象
return true;
} else {
return false;
}
}
注意,String类已经重写了equals()方法,他比较的是两个String类型的值是否相等,并不是比较地址。
二、hashCode方法
1、hashCode()是什么方法?
与hashCode()方法紧密联系的是HashMap和HashSet集合,其中HashSet是基于HashMap实现的,所以接下来我们以HashMap()为例,介绍一下HashMap存储键值对的机制:首先对于每个Key,hashCode()方法会根据地址计算出一个值,根据这个值来确定这个对象在HashMap集合中的位置。
2、为什么要重写hashCode方法?
由上面可以知道,在HashMap集合中存储对象时,是根据hashCode()方法的返回值来决定存储在集合中的哪个位置,而hashCode()方法是根据对象的地址来计算的。如果我们new两个对象,使得他们在我们的判断标准下是同一对象,由于是new出来得两个对象,因此他们的地址一定不相同,所以他们一定存在集合中的不同位置。导致集合中出现两个对象。所以我们要重写hashCode方法。
3、如何重写hashCode方法
以上面的例子为例,我们再添加一个属性age,即两个对象的身份证号与年龄都相等时,我们认为是同一对象:
@Override
public int hashCode() {
int result = number.hashCode();
result = 17 * result + age.hashCode();
return result;
}
从上面这段代码可以看出,重写hashCode的方法是:先找出判断对象相等需要的属性,在这个例子中就是身份证号number和年龄age,然后取一个小整数(一般是质数),本例中是17,然后计算17*属性的hashcode+其他属性的hashcode,重复步骤。
三、equals与hashCode
1、首先需要明确的是重写equals()不一定非要重写hashCode()方法,只有当我们用到HashSet,HashMap等集合时,才需要重写hashCode()方法,但是由于我们很难保证在程序不用到这些集合,所以我们一般说重写equals方法就一定要重写hashCode方法。
2、当两个对象调用equals返回是true时,这两个对象应该返回相同的hashCode值。
3、当两个对象调用equals返回是false时,这两个对象的hashCode值可能相同也可能不同。
4、当两个对象的hashCode值相同时,他们调用equal是的结果可能时true也可能是false。
5、当两个对象的hashCode值不同时,他们调用equal是的结果一定是false。