为什么重写equals方法之后必须要重写hashCode

文章讲述了在Java中重写equals和hashCode方法的原因。默认的equals只比较对象引用,而重写equals用于内容比较。不重写hashCode可能导致在使用散列表(如HashSet或HashMap)时,内容相同的对象被视为不同,从而引入错误。因此,通常在重写equals后也应该重写hashCode,以确保散列操作正确处理相等的对象。
摘要由CSDN通过智能技术生成

目录

1. 要注意的点

2. 为什么要重写equals方法?

3. 重写equals但不重写hashCode会出现什么问题?

4. 什么是散列表

5. 总结结论


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 一并重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值