目录
3. 重写equals但不重写hashCode会出现什么问题?
1. 要注意的点
(1)重写 equals 不重写 hashCode 运行时并不会报错,但是在逻辑上会报错;
(2)并不是每次重写 equals 都必须重写 hashCode,但推荐都写上去;
2. 为什么要重写equals方法?
原因很简单,默认的 equals 方法无法满足我们的正常开发需求,我们需要对它进行重写升级。
我们先来看一下所有类的祖宗 Object 类中 equals 方法的代码,这可以让我们理解为什么要重写equals。
可以看出,在 Object 类的源码中,它的 equals 方法就是很简单的用了 "==" 来判断了一下。众所周知,== 是对类对象的引用做判断,判断引用是否相等。
所以默认的 equals 的逻辑就是判断的双方是否引用了一个对象,如果是那就是相等的,如果不是那就不相等。
默认的 equals 看似能满足我们的要求,但有些情况下却不能。在开发过程中,我们更希望比较的是两个对象的内容是否相等。
比如两个字符串,String a = "123456",String b = "123456",内容完全一样,在我们看来这两个字符串就是相等的。但在 equals 方法看来,两个字符串的内存地址不相等,所以仍然会判定为不相等,这就与我们期望的判断结果发生了矛盾,所以需要去重写 equals 方法,只有重写了equals 方法之后,我们再去判断 a 和 b,此时判断结果就会相等。
3. 重写equals但不重写hashCode会出现什么问题?
我们来看下面这段代码:
public class EqualsAndHashcode {
public static void main(String[] args) {
people people1 = new people();
people people = new people();
System.out.println(people.equals(people1));
}
}
class people{
private String name;
private int age;
public people(){
name = "李华";
age = 18;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if (obj==null){
return false;
}
if(getClass() != obj.getClass()){
return false;
}
people other = (people) obj;
return Objects.equals(name,other.name)
&&age == other.age;
}
}
可以看出,对于两个具有初始化 people 对象,equals 是可以满足我们的要求的。
上面的代码看似没有问题,达到了我们想要的结果,但这只是因为我们还没有遇到是它犯错的情况:散列表。
4. 什么是散列表
先介绍一下散列表的工作原理,简单来说就好比是一个货物架,货物架上的每个位置只能放一个商品,我们拿到一个货物之后,需要先找到这个货物对应应该存放的位置,然后就把它放到对应的位置。
hashCode 就是这样,它会先计算对象的哈希值 ,然后通过哈希值找到它该存放的位置,如果这个位置是空的,就直接放上去;如果这个地方已经放有货物了,就用 equals 比较一下要放置的货物和当前已经存放的货物是不是同一个,如果是同一个就不放了,不是的话就会把它放在另一个位置。
为什么遇到散列表,上面的代码就会出错呢?原因就是哈希函数,既然我们想让两个属性一样的类对象是为相等,那么在散列表中也应当如此。
如下代码:
照这么看来,上面的代码还能满足我们的要求吗?
很明显,set 里面有两个元素,虽然我们认为这两个元素是一样的,可 set 不这么认为。这样显然不是我们想要的结果,他俩明明就相同,为什么还要加进去呢?
到这这个结果的罪魁祸首相比大家都知道了吧,就是因为哈希函数。
我们先来看看 Object 中的 hashCode 是怎么样的:
我们再来打印一下这两个people对象的hashCode来看一下:
从结果就可以看出来,这两个 people 是不一样的,所以把他们两个都放进去也就合情合理了。
到这里,我们就知道问题的原因了,重写 hashCode 的可以保证我们的散列表不会存放重复的值。
5. 总结结论
结论一:equals 和 hashCode 方法是 Object 类中的方法,而 Object 类是所有类的祖宗类,所以每个类中都存在 equals 和 hashCode,如果不重写,就是默认 Object 类中的实现。
结论二:当我们重写 equals 后,如果要放入哈希表中,则要重写 hashCode 来保证不会重复放入相同的值。所以,建议当重写了 equals 之后,将 hashCode 一并重写。