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

前言

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

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

什么是hashCode?

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

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()),它们必须有相同的哈希值,否则会影响集合类(如HashSetHashMap)的正常工作。

举个例子:

假设我们有两个内容相同的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()保证性能上的高效。

两者的重要性体现在:

  • 在集合类中(如HashSetHashMap),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:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享

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

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

相关推荐
J2虾虾1 分钟前
Java Lambda 表达式详解文档
java·开发语言
longxibo6 分钟前
【第1章 环境搭建与项目结构解析】
java·后端·流程图
a***72897 分钟前
Java进阶(ElasticSearch的安装与使用)
java·elasticsearch·jenkins
Java成神之路-12 分钟前
面试题:Spring AOP底层实现原理
java·spring aop
Python私教15 分钟前
如意Agent日志系统重构:从 print() 大海捞针到结构化可观测性栈
java·前端·重构
jieyucx20 分钟前
Go 零基础数据结构:顺序表(像「排抽屉」一样学增删改查)
java·数据结构·golang
曦夜日长21 分钟前
C++ STL容器string(一):string的变量细节、默认函数的认识以及常用接口的使用
java·开发语言·c++
北山有鸟27 分钟前
IS_ERR 判断出错后,再用 PTR_ERR 把它强制转换回 int 型的错误码作为函数的返回值。
java·开发语言
程序员老邢31 分钟前
【产品底稿 11】架构规整收官:从混乱到清晰,工程结构、表命名、模块分层一次性定型
后端·架构·springboot·产品底稿·架构规整·模块分层·数据库规范
phltxy33 分钟前
深度解析:Spring Cloud Gateway 从入门到实战
java·开发语言