为什么重写 equals 时必须重写 hashCode 方法?

先说结论:因为不重写的话,那么当你创建这个类的HashMap(key)、HashSet等不允许元素重复的散列表并塞入数据时,可能会出现重复的元素。

这是因为散列表中判断元素重复时,会先判断hashcode是否相等,相等后才会比较equals。如果hashcode不相同的就直接判断为不同元素。

为什么散列表不直接比较equals呢?
因为hash算法是二进制算法,计算式本质是二进制,所以hash算法速度很快。说白了还是为了效率。

而你不重写hashCode()方法,会造成业务上认为的相同元素会拥有不同的hashcode。这是由于hashcode是由对象导出的一个整型值,如果x与y是两个不同的对象,那么x.hashCode()与y.hashCode()基本是不会相同的。所以只要是两个对象,即使两个内容完全相同,hashcode基本上也是不会相同的。

验证一下,首先我们先创建一个Person类,并重写equals方法(先不重写hashCode方法)

@AllArgsConstructor
public class Person {
    private String name;    
    private String sex;    
    public String getName() {        
        return name;    
    }    
    
    public void setName(String name) {
        this.name = name;    
    }    
    
    public String getSex() {
        return sex;    
    }    
    
    public void setSex(String sex) {
        this.sex = sex;    
    }    
    
    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", sex=" + sex +
            '}';    
    }    
    
    @Override    
    public boolean equals(Object o) {
        if (this == o) return true;        
        if (o == null || getClass() != o.getClass()) 
            return false;        
        Person person = (Person) o;       
        return Objects.equals(name, person.name) &&                
            Objects.equals(sex, person.sex);    
    }
}

然后new两个内容一样的Person实例,比较一下equals是否相等,再将其分别放入HashSet中,打印一下set中的内容。

    public static void main(String[] args) {
        Person person1 = new Person("Van Darkholme","♂");
        Person person2 = new Person("Van Darkholme","♂");

        System.out.println(person1.equals(person2));

        Set<Person> set = new HashSet<>();

        set.add(person1);
        set.add(person2);

        System.out.println(set.toString());
    }

我们知道HashSet中是不会拥有重复元素的。所以上面程序我们期望set中只有一个元素。

运行一下:

true
[Person{name='Van Darkholme', sex=♂}, Person{name='Van Darkholme', sex=♂}]

发现两个元素equals为true,说明两个元素相等,但是set中却出现了两个相同的元素。

看一下HashSet中add的源码,跟踪到HashMap的putVal方法。

在这里插入图片描述

我们可以看到方法中先比较元素的HashCode,如果相等再比较是否==或者equals是否为true,条件都成立才会元素替换。

我们通过打印的HashCode发现,两个实例的hashCode不同,当然也就不会进行equals的判断了。直接判断两个元素不同。

person1:966808741
person2:1908153060

相同的原理,如果重写equals不重写hashCode,HashMap中的key也会出现一样的问题。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值