JAVA为什么要重写equals方法?重写了equals方法后为什么要重写hashcode方法?

为什么需要重写equals方法?

比方创建一个Student类,定义了一个全参构造方法

public class Student {
    private String name;
    private Integer stuId;

    public Student(String name, Integer stuId) {
        this.name = name;
        this.stuId = stuId;
    }
}

这时需要根据学生的姓名和唯一学号判断是不是同一个人

    public static void main(String[] args) {
        Student stu1 = new Student("张三", 20);
        Student stu2 = new Student("张三", 20);
        System.out.println(stu1.equals(stu2));
    }

逻辑上可以根据学生的姓名和学号是否相等来判断是不是同一个人,那么这时stu1和stu2就应该是一个人,即stu1.equals(stu2)打印的结果是true才符合逻辑,看看结果
在这里插入图片描述
为什么打印的结果却为false?我们查看一下Student类的equals方法

    public boolean equals(Object obj) {
        return (this == obj);
    }

可以看到Student类的equals方法是继承的Object类,即stu1.equals(stu2)实际上是返回的stu1==stu2的值,==运算符是比较两个对象的内存地址值,stu1和stu2是指向的两个不同的对象,所以他们的内存地址值肯定不一样
这种情况下,是不是需要自己重写Student中的equals方法才能判断出stu1和stu2是否相等?
通过idea的自动生成equals方法,再看看现在的Student类

public class Student {
    private String name;
    private Integer stuId;

    public Student(String name, Integer stuId) {
        this.name = name;
        this.stuId = stuId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Student)) {
            return false;
        }
        Student student = (Student) o;
        return Objects.equals(name, student.name) &&
                Objects.equals(stuId, student.stuId);
    }
}

equals首先判断两个对象的内存地址是否相同,再判断是否是同一地址,最后再判断里面的属性值是否相等,所以这时再执行stu1.equals(stu2),结果就是true了,在以后逻辑中就可以通过姓名和学号判断是否是同一个学生了
在这里插入图片描述

为什么重写了equals方法后要重写hashcode方法?

我们知道,在HashMap里面,如果key重复的话,就会覆盖以前的值,那么看下面代码简单测试一下
在这里插入图片描述

再看一下用Student做为key时的打印结果

    public static void main(String[] args) {
        Student stu1 = new Student("张三", 20);
        Student stu2 = new Student("张三", 20);
        Map<Student, Integer> map = new HashMap<>();
        map.put(stu1, 1);
        map.put(stu2, 2);
        System.out.println(map);
    }

上面代码stu1.equals(stu2)相等,也是我们认为的逻辑上相等,那么打印的结果,也应该是下面的操作把上面的值覆盖了才合理,看看打印结果
在这里插入图片描述
这里竟然打印了两个值, 不合理啊,为什么不合理呢?
因为在HashMap中,是根据key的hashcode值确定数组下标位置的,如果数组下标位置相同,先比较key的hashcode值,如果相同,再用equals方法对比,如果相等,则覆盖,所以刚刚map.put(1,2)能够覆盖第一个操作,是因为他们的key都是1,所以他们的hashcode是相等,同样hashmap计算他们的数组下标位置也是相同的
所以我们看看我们的stu1和stu2的hashcode值是否相等
在这里插入图片描述

发现他们的值并不一样,我们看看hashcode方法源码

 public native int hashCode();

这是一个本地方法,它的实现与本地机器有关,这里我们暂且认为他返回的是对象存储的物理位置。
stu1和stu2本来就是在堆内存中的两个不同的对象,他们的物理地址值肯定不相同了,但是他们的name属性和stuId相等,在我们的逻辑里相等的,我们需要他们equals相等,重写了equals方法,现在需要他们hashcode也相等,是不是应该也重写他们的hashcode方法?
利用idea自动重写hashcode后Student类如下

public class Student {
    private String name;
    private Integer stuId;

    public Student(String name, Integer stuId) {
        this.name = name;
        this.stuId = stuId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Student)) {
            return false;
        }
        Student student = (Student) o;
        return Objects.equals(name, student.name) &&
                Objects.equals(stuId, student.stuId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, stuId);
    }
}

再打印一下他们的hashcode值看看
在这里插入图片描述
发现hashcode值相等了,我们再试试map里面能否覆盖
在这里插入图片描述
发现覆盖成功了,所以现在知道为什么重写了equals方法后必须要重写hashcode方法了吧

总结

在java里面,如果两个对象的hashcode相等,他们equals对比却不一定相等,如果两个对象equals对比相等,他们的hashcode值一定相等
所以不光在HashMap里面是先比较hashcode值再比较equals,在HashTable或HashSet里面也是这样的逻辑,因为先比较hashcode仅为一个int值,比较的效率更高,可以更快速的排除不相等的情况。

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值