为什么重写equals()方法时必须要重写hashCode()方法

为什么重写equals()方法时必须要重写hashCode()方法

首先我们需要弄清楚equals()方法和hashCode()方法是什么?

**equals()**方法用于判断两个对象是否想同,不能用于比较基础类型的数据。equals()方法是存在于Object类中的,他是所有类直接或间接的父类,所以,所有的类都有equals()方法。

**hashCdoe()**方法是用于获取哈希码的,哈希码是一个int类型的整数,用于确定对象在哈希表中的索引位置。哈希码在Java中的作用是,在具有哈希结构的容器中,如HashTable、HashMap、HashSet。在向这些容量里面添加对象的时候,会先使用hashCode()方法计算该对象的哈希码,如果哈希码相同,会使用equals()方法来判断两个对象是否真的相同,如果相同就不会让其加入该位置;如果不同则让其加入。这样可以减少equals()的执行次数从而提高执行效率,因为equals()方法的开销是比hashCode()方法的开销大的。hashCode()方法和equals()方法一样是存在于Object类中的

那么为什么重写了quals()方法时必须要重写hashCode()方法呢?

我们知道如果两个对象相等,他们的hashCode是一定相等的,且他们调用equals()方法比较返回的结果一定是true。但是如果两个对象的hashCode相同,他们不一定是相等的(可能产生了哈希碰撞),所以equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。

下面我们来举例说明一下,这是我自定义的一个Person类,里面有id(身份证)、phoneNum(电话号码)两个属性。

public class Person {
    
    private int id;
    
    private int phoneNum;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(int phoneNum) {
        this.phoneNum = phoneNum;
    }
}

我们假设只要id(身份证)相同的两个Person他们就是同一个人,如果我们不重写equals()方法,这两个对象不会是同一个人

public static void main(String[] args) {
        Person person1 = new Person(666666, 1888888888);
        Person person2 = new Person(666666, 1666666666);
        System.out.println(person1.equals(person2));  // 结果为:false
    }

如果我们要让具有相同id的Person为同一个人的话,我们需要重写eauals()方法,注意,此时我们没有重写hashCode()方法

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id;
    }

重写equals()方法之后,我们再次运行结果为true,说明这两个Person是同一个人了

public static void main(String[] args) {
        Person person1 = new Person(666666, 1888888888);
        Person person2 = new Person(666666, 1666666666);
        System.out.println(person1.equals(person2));  // 结果为:true
    }

此时我们把这个两个person放入具有哈希结构的容器中,我们将这两个Person放入HasSet中

public static void main(String[] args) {
        Person person1 = new Person(666666, 1888888888);
        Person person2 = new Person(666666, 1666666666);
        Set<Person> set = new HashSet<>();
        set.add(person1);
        set.add(person2);
        System.out.println(person1.equals(person2));  // 结果为:true
        System.out.println(set.size());  // 结果为:2
    }

因为我们规定了具有相同id(身份证)的Person为同一个人,所以person1.equals(person2)为“true”,这样的话set里面的大小应该为1,但结果是为2,说明在HashSet看来这两个Person还不是同一个人。这是因为HashSet在添加对象的时候会先调用hashCode()方法计算哈希码,来确定该对象在哈希表中的索引位置。我们没有重写hashCode()方法,当计算person1和person2的哈希码的时候,是不同的,HashSet就会认为这两个对象时不同的,但此时equals()方法返回的结果是true,这就造成了结果的不一致。

所以,我们需要重写hashCode()方法来保证结果的一致性,我们重写hashCode()方法

@Override
    public int hashCode() {
        return Objects.hash(id);
    }

再次运行程序,可以发现此时set的大小为1了,与我们预期的结果是一致的,这就是为什么重写equals()方法必须要重写hashCode()方法。

public static void main(String[] args) {
        Person person1 = new Person(666666, 1888888888);
        Person person2 = new Person(666666, 1666666666);
        Set<Person> set = new HashSet<>();
        set.add(person1);
        set.add(person2);
        System.out.println(person1.equals(person2));  // 结果为:true
        System.out.println(set.size());  // 结果为:1
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值