Java中为什么重写equals方法时还要重写hashCode方法?

参考:https://blog.youkuaiyun.com/en_joker/article/details/133670740

https://www.mianshiya.com/bank/1787463103423897602/question/1772568783219695618#heading-1

首先分清楚:

hashCodeequals == 都是Java中用于比较对象的三种方式,但是它们的用途和实现还是有很大区别的。

  • hashCode用于散列存储结构中确定对象的存储位置,可用于快速比较两个对象是否不同、因为如果它们的哈希码不同、那么它们肯定不相等。

  • equals用于比较两个对象的内容是否相等,通常需要重写自定义比较逻辑。

  • ==用于比较两个引用是否指向同一个对象(即内存地址)。对于基本数据类型,比较它们的值。

其中hashCode默认由Object类根据对象的内存地址生成哈希码

所以,需要注意的是哈希表进行==!=比较时,

如果重写了hashCode()方法的话,hashCode一样的,==不一定判断相等

如果没有重写的话,hashCode一样的,==能判断相等

(1)需要重写hashCode方法的原因:

因为在Java中,哈希表使用哈希码来确定存储对象的位置。如果两个相等的对象具有不同的哈希码,那么它们将被存储在哈希表的不同位置(不在同一个哈希桶中),导致无法正确查找这些对象。(比如无法正常使用contains,get方法等等)

例子如下:
package com.wb;

import java.util.*;

public class IncorrectKey {
    private final String value;
    private final int randomHash; // 用于模拟错误的哈希码生成
    private final int rightHash; // 用于模拟正确的哈希码生成
    public IncorrectKey(String value) {
        this.value = value;
        this.randomHash = (int) (Math.random() * 1000); // 错误:哈希码基于随机值
        this.rightHash = Objects.hash(value);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        IncorrectKey that = (IncorrectKey) o;
        return value.equals(that.value); // 正确:仅比较 value 是否相等
    }

    @Override
    public int hashCode() {
        //return randomHash; // 错误:哈希码与 equals 比较的 value 无关
        return rightHash;// 正确:重写哈希码,两个对象不一定是同一个地址,但是会被放到同一个哈希桶中
    }

    public static void main(String[] args) {
        System.out.println("--------------例子1,HashMap-----------------");
        Map<IncorrectKey, String> map = new HashMap<>();

        IncorrectKey key1 = new IncorrectKey("key");
        IncorrectKey key2 = new IncorrectKey("key"); // key1.equals(key2) 为 true

        map.put(key1, "Value1");

        //虽然equals相等,但是Hash中,必须使hashCode相等
        System.out.println(key1.equals(key2));// 一直都是true
        // 尝试用 key2 获取值
        String result = map.get(key2);
        System.out.println("查找到的值: " + result); // rightHash对应"Value1",randomHash对应null


        System.out.println("--------------例子2,HashSet-----------------");
        // HashSet
        Set<IncorrectKey> set = new HashSet<>();
        set.add(key1);
        System.out.println(set.contains(key2));//rightHash对应true,randomHash对应false
    }
}

(2)需要重写equals方法的原因:

contains原理如下:

所以才需要重写equals方法。(但是实际上涉及到Hash相关的数据结构,还要同时重写hashCode方法!

(3)两者需一起用,例子如下:

package com.wb;

import java.util.Objects;

public class Students {
    String name;
    int age;

    public Students(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;
        Students students = (Students) o;
        return name.equals(students.name) && age == students.age;
        //return Objects.equals(name,students.name) && age == students.age;//等效于上面,两种相同效果的equals调用方法。
    }

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

    public static void main(String[] args) {
        // 假如这样重写hashCode和equals
        Students s1 = new Students("20", 24);
        Students s2 = new Students("20", 24);
        Students s3 = s1;
        // 默认是引用指向的对象的内存地址得出的hashCode
        System.out.println(s1.hashCode() + "==" + s3.hashCode());// 打印50523==50523

        System.out.println(s1.equals(s2)); //打印true
        System.out.println(s1.hashCode() + "==" + s2.hashCode());// 打印50523==50523
        System.out.println(s1 == s2);//打印false
        //由此看出,如果重写了hashCode()方法的话,hashCode一样的,==不一定判断相等
        //如果没有重写的话,hashCode一样的,==能判断相等

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值