Java基础面试题06:hashCode()和equals()方法的重要性体现在什么地方?

前言

Java中的hashCode()和equals()方法看似是干同一件事,但它们的使用场景和作用却大有不同。为了让程序更高效、更准确地运行,我们需要对这两者有深入的了解,并掌握它们的重写规则。

hashCode()和equals()的基础知识

什么是hashCode?

hashCode()是用来返回一个哈希值 (int类型)的,它的作用是确定对象在散列表(如HashMap或HashSet)中的存储位置。

java 复制代码
public class Demo {
    public static void main(String[] args) {
        String str = "aa";
        System.out.println(str.hashCode());  // 输出结果为3104
    }
}
  • 哈希值的作用
    可以把哈希值看成是对象的身份证号,散列表会根据这个"身份证号"快速定位到对象的位置。
  • 定义在哪
    hashCode()方法定义在java.lang.Object类中,这意味着所有类都默认拥有这个方法。

什么是equals?

equals()方法用于比较两个对象是否"相等"。

默认情况下,它和==一样,比较的是对象的内存地址 。但是,开发中我们经常需要比较对象的内容,比如两个学生对象的名字是否相等,这时就需要重写equals()方法。


hashCode()和equals()的关系

两条重要结论

  1. 如果两个对象通过equals()方法比较相等,它们的hashCode()值必须相等 。
    (也就是说:equals()是绝对可靠的。)
  2. 如果两个对象的hashCode()值相等,它们通过equals()方法比较时不一定相等 。
    (这意味着:hashCode()是相对可靠的。)

这两个结论很重要,后面会用它们来解释为什么要同时重写hashCode()和equals()。


为什么要重写equals()?

默认情况下,equals()方法比较的是两个对象的内存地址。如果两个对象的地址不同,即使它们的内容完全一样,equals()也会返回false。

举个例子:

java 复制代码
class Person {
    String name;

    Person(String name) {
        this.name = name;
    }
}

public class Demo {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");

        System.out.println(p1.equals(p2));  // false
    }
}

如何重写equals()?

如果我们希望两个name相同的Person对象被认为是相等的,就需要重写equals()方法:

java 复制代码
@Override
public boolean equals(Object obj) {
    if (this == obj) return true; // 自反性
    if (obj == null || getClass() != obj.getClass()) return false;
    Person person = (Person) obj;
    return Objects.equals(name, person.name);
}

重写equals()需要遵守的规则

  • 自反性 :x.equals(x)必须返回true。
  • 对称性 :如果x.equals(y)为true,那么y.equals(x)也必须为true。
  • 传递性 :如果x.equals(y)为true,并且y.equals(z)为true,那么x.equals(z)也必须为true。
  • 一致性 :如果两个对象没有变化,多次调用x.equals(y),结果必须一致。
  • 非空性 :x.equals(null)必须返回false。

为什么要重写hashCode()?

当我们重写了equals(),还必须重写hashCode()。

这是因为,如果两个对象被认为是相等的(通过equals()),它们必须有相同的哈希值,否则会影响集合类(如HashSet、HashMap)的正常工作。

举个例子:

假设我们有两个内容相同的Person对象:

java 复制代码
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
  • 如果只重写了equals():
    • HashSet可能会认为它们是两个不同的对象,导致HashSet中存储了重复数据。
  • 如果同时重写了hashCode():
    • HashSet会根据相同的哈希值,将它们识别为同一个对象,避免重复存储。

重写hashCode()的方法

在重写hashCode()时,应该确保相等的对象有相同的哈希值 。通常,可以通过Objects.hash()方法快速生成哈希值。

java 复制代码
@Override
public int hashCode() {
    return Objects.hash(name);
}

总结:hashCode()和equals()的搭配使用

简单记住:

  1. 如果重写了equals(),一定要重写hashCode()。
  2. equals()保证逻辑上的相等,hashCode()保证性能上的高效。

两者的重要性体现在:

  • 在集合类中(如HashSet、HashMap),hashCode()用于快速定位,equals()用于最终确认是否相等。
  • 通过正确重写这两个方法,可以避免重复数据、保证集合操作的准确性。

参考代码示例:综合重写equals()和hashCode()

java 复制代码
class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

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

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

public class Demo {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");

        System.out.println(p1.equals(p2));  // true

        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);

        System.out.println(set.size());  // 1
    }
}

通过这个示例,可以看到两个name相同的Person对象在HashSet中只存储一次。


掌握了这些,你就能够在面试中清晰地解释hashCode()和equals()的作用及它们之间的关系啦!

最后说一句(求关注,求赞,别白嫖我)

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。 这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏

点赞对我真的非常重要!在线求赞,加个关注我会非常感激!

相关推荐
蛋蛋的就会顺顺的2 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i2 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8263 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡3 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林4 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne5 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF5 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_5 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li5 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
省钱兄--zs5 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构