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

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

​ 了解这个问题之前我们得需要知道hashCode的作用。equals方法和hashCode方法都是Object类中的基础方法,用来判断两个对象是否相等。而平时我们比较两个对象不是用equals来比较吗?为什么又需要hashCode呢?原因就在于hashCode能够提升性能。
​ 例如我们常用的HashMap这个容器来说,它是通过键hashCode来计算出索引位置(存储位置)的,如果没有hash那就只能遍历元素相比下效率低于hash定位。
​ 那为什么不能直接使用hashCode就确定元素相等呢?下面看一段代码
在这里插入图片描述
​ 通过这段代码可以看出不同的对象hashCode可能一样,那为什么重写了equals方法要重写hashCode呢?原因就是比较对象相等首先要比较hashCode是否相等,如果hashCode相等才会去比较equals,下面通过代码来验证

/**
 * 定义一个实体类
 * @Data注解为lombok注解也可以自己写getter和setter方法
 */
@Data
class A {
    private String name;
    private int age;

    public A(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        A a = (A) o;
        return age == a.age && Objects.equals(name, a.name);
    }
}

​ A类中只重写了equals方法并没有重写hashCode方法,下面使用A作为HashMap的键来测试

public class Test {
    public static void main(String[] args) throws Exception {
        Map<A, Integer> map = new HashMap<>();
        A a1 = new A("zhangsan", 12);
        A a2 = new A("zhangsan", 12);
        // 调用equals方法判断相等
        System.out.println(a1.equals(a2));
        map.put(a1, 1);
        map.put(a2, 2);
        System.out.println("-------------");
        map.forEach((k, v) -> System.out.println(k + "---> " + v));
    }
}

在这里插入图片描述
​ 运行代码可以看出对象相等但是map中的键并没有覆盖,可见在比较对象相等前先会判断对象hashCode是否相等,下面我们把A类中的hashCode方法一起重写

/**
 * 定义一个实体类
 * @Data注解为lombok注解也可以自己写getter和setter方法
 */
@Data
class A {
    private String name;
    private int age;

    public A(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        A a = (A) o;
        return age == a.age && Objects.equals(name, a.name);
    }

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

​ 再次运行代码结果如下:

​ map中的键发生了覆盖,出现以上问题的原因是,如果只重写了 equals 方法,那么默认情况下,会先判断两个对象的 hashCode 是否相同,此时因为没有重写 hashCode 方法,所以会直接执行 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法对比的是两个不同引用地址的对象,所以结果是 false,那么 equals 方法就不用执行了,直接返回的结果就是 false:两个对象不是相等的,于是就在 map集合中插入了两个相同的对象的键

小结

​ hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,如果在重写 equals 时,不重写 hashCode,就会导致在某些场景下,例如将两个相等的自定义对象存储在 map集合时,就会出现程序执行的异常,为了保证程序的正常执行,所以我们就需要在重写 equals 时,也一并重写 hashCode 方法才行。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coder-ren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值