当前位置: 首页 > news >正文

Java 中 `equals()`、`==` 和 `hashCode()` 的区别

Java 中 equals()==hashCode() 的区别

1. == 运算符

作用

  • 对象引用比较:用于判断两个对象的引用地址是否一致,即判断两个引用是否指向内存中的同一个对象实例。
  • 基本数据类型比较:对于基本数据类型(如 intbooleandouble 等),== 直接比较它们的值。

示例

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");System.out.println(s1 == s2);  // true(字符串常量池优化,s1 和s2指向常量池中的同一个字符串对象)
System.out.println(s1 == s3);  // false(s3是通过 `new` 关键字在堆中创建的新对象,与s1地址不同)

在这个例子中,s1s2 由于字符串常量池的优化机制,它们指向相同的内存地址,所以 s1 == s2 返回 true;而 s3 是通过 new 操作在堆中创建的新对象,其内存地址与 s1 不同,因此 s1 == s3 返回 false

2. equals() 方法

作用

  • 默认行为:在 Object 类中,equals() 方法的默认实现与 == 相同,即比较两个对象的引用地址。
  • 重写场景:在实际应用中,往往需要根据业务逻辑来定义对象的“相等性”。例如,对于一个 User 对象,可能认为只要 id 相同就表示这两个 User 对象相等,而不关心它们是否是同一个内存实例。这就需要重写 equals() 方法来实现这种自定义的相等性判断。

重写规则

  • 对称性:如果 a.equals(b) 返回 true,那么 b.equals(a) 也必须返回 true。这确保了相等性判断的一致性,无论从哪个对象发起比较。
  • 传递性:若 a.equals(b)trueb.equals(c)true,那么 a.equals(c) 也应为 true。这有助于在多个对象之间建立一致的相等性关系。
  • 一致性:在对象的状态没有被修改的情况下,多次调用 equals() 方法应该返回相同的结果。
  • 非空性:对于任何非空对象 aa.equals(null) 必须返回 false

示例

class User {private int id;private String name;@Overridepublic boolean equals(Object o) {if (this == o) return true; // 如果是同一个对象引用,直接返回trueif (o == null || getClass() != o.getClass()) return false; // 如果o为null或者类型不同,返回falseUser user = (User) o;return id == user.id && Objects.equals(name, user.name); // 比较id和name是否相等}
}

在上述 User 类中,重写的 equals() 方法首先判断两个对象是否为同一个引用,如果是则直接返回 true。然后检查传入对象是否为 null 以及类型是否匹配,若不满足则返回 false。最后比较 idname 属性,只有当这两个属性都相等时才认为两个 User 对象相等。

3. hashCode() 方法

作用

  • 哈希表操作支持hashCode() 方法返回对象的哈希值,主要用于在哈希表(如 HashMapHashSet)中进行快速查找和存储。哈希表通过对象的哈希值来确定对象在表中的存储位置,从而提高查找和插入的效率。
  • equals() 方法的关联:按照规定,如果两个对象通过 equals() 方法比较返回 true,那么它们的 hashCode() 值必须相同。这是为了保证在哈希表中,相等的对象能够被正确地存储和检索。

常见错误

  • 未重写 hashCode():当重写了 equals() 方法但没有相应地重写 hashCode() 方法时,会导致在使用哈希表时出现异常。例如,将两个 equals()true 的对象放入 HashSet 中,由于它们的 hashCode() 值不同,HashSet 可能会认为这是两个不同的对象,从而违背了集合的唯一性原则。

示例

class User {private int id;private String name;@Overridepublic int hashCode() {return Objects.hash(id, name);}
}

在这个 User 类中,使用 Objects.hash() 方法生成哈希值,它结合了 idname 属性来计算哈希值,保证了相等的 User 对象(根据 equals() 方法判断)具有相同的哈希值。

4. 三者的关系

场景==equals()hashCode()
比较引用地址❌(默认同 ==
比较对象内容(业务逻辑)✅(需重写)
哈希表存储❌(依赖 hashCode()
  • 比较引用地址== 直接用于比较对象引用地址;equals()Object 类的默认实现下也比较引用地址,但通常会被重写以比较对象内容;hashCode() 与比较引用地址无关。
  • 比较对象内容(业务逻辑)== 不适合用于比较对象内容;equals() 需要重写才能按照业务逻辑比较对象内容;hashCode() 本身不用于比较对象内容,但与 equals() 配合保证哈希表操作正确。
  • 哈希表存储==equals() 都不直接用于哈希表存储定位;hashCode() 用于哈希表中对象的快速定位和存储,且相等对象(equals()true)的 hashCode() 必须相同。

5. 最佳实践

  • 重写一致性:当重写 equals() 方法时,必须同时重写 hashCode() 方法,以确保在使用哈希表相关的集合(如 HashMapHashSet)时,对象能够被正确地存储和检索。否则,可能会出现重复元素或无法正确获取元素的问题。
  • 使用工具生成:现代 IDE(如 IntelliJ IDEA)提供了自动生成 equals()hashCode() 方法的功能,生成的代码通常符合上述规则,可以避免手动编写可能出现的错误。
  • 字符串比较:在比较字符串时,应始终使用 equals() 方法而不是 ==。同时要注意避免空指针异常,如示例中的 if ("test".equals(s)) 这种写法可以防止 snull 时抛出 NullPointerException

错误示例

String s = null;
if (s == "test") {  // 可能空指针异常// 逻辑
}// 正确写法
if ("test".equals(s)) {// 逻辑
}

在错误示例中,如果 snull,使用 s == "test" 会抛出 NullPointerException;而正确写法中,"test".equals(s) 可以避免这种情况,因为 String 类的 equals() 方法在处理 null 参数时会返回 false

6. 面试高频问题

  • 为什么 String 类重写了 equals()hashCode()

    • 答案String 类重写 equals() 是因为字符串的相等性通常基于其内容(字符序列),而不是引用地址。例如,两个不同的 String 对象只要字符序列相同,就应该被认为是相等的。重写 hashCode() 则是为了配合 equals() 方法,确保在哈希表等数据结构中,相等的字符串对象具有相同的哈希值,从而保证哈希表操作的正确性和高效性。
  • 如果两个对象 hashCode() 相同,equals() 一定为 true 吗?

    • 答案:不一定。这是因为可能存在哈希冲突的情况,即不同的对象由于哈希算法的特性,计算出了相同的哈希值。所以,仅仅哈希值相同并不能确定两个对象在业务逻辑上是相等的,还需要通过 equals() 方法进一步判断。在实际应用中,可以通过合理设计哈希算法来尽量减少哈希冲突的概率,但无法完全避免。
http://www.dtcms.com/a/460957.html

相关文章:

  • 成像系统(十四-1:《工业级ISP流水线:ISP前端处理 - 从原始数据到可用图像》):从LED冬奥会、奥运会及春晚等大屏,到手机小屏,快来挖一挖里面都有什么
  • vue-router(vue 路由)基本使用指南(二)
  • 深入理解 Java中的 异常和泛型(指南十二)
  • 草莓植物(plant)【高精度-->array高级!!!】
  • 3D 图表、堆叠饼图为什么是灾难?
  • Nacos 全解析:从注册中心到配置管理的实战指南
  • 微信小程序开发从零基础到项目发布的全流程实战教程(四)
  • wordpress 全站静态二次开发小程序
  • linux命令--后端项目部署
  • 网页版云手机 梦幻西游手游
  • HTML5 与 HTTPS,页面能力、必要性、常见问题与实战排查
  • 网站检索功能怎么做建设宣传网站的必要性
  • 做网站维护需要懂什么网站建设洽谈问题
  • 17、Linux 文件压缩与解压
  • IDEA编译时报错OOM的解决方案
  • .NET驾驭Word之力:基于规则自动生成及排版Word文档
  • 本地web测试服务器快速域名映射工具
  • 自己搭建远程桌面服务器——私有化部署RustDesk
  • 机器人强化学习原理讲解二:关于机器人重置
  • 目标检测YOLO实战应用案例100讲-相机 ISP(三)
  • 网站无障碍建设标准we建站
  • Linux系统为普通用户设置sudo权限
  • 网络流量分析工具
  • 网站基站的建设网站建设学习哪家专业
  • 【渗透测试】ARP是什么?有什么作用?
  • JavaEE 初阶第二十八期:HTTP协议深度揭秘(二)
  • 【Linux命令从入门到精通系列指南】source 命令详解:在当前 Shell 中执行脚本的终极指南
  • 深入理解 OKHttp:设计模式、核心机制与架构优势
  • 电压互感器在电网中接线方式决定了一次消谐器如何安装
  • HAMi 2.7.0 发布:全面拓展异构芯片支持,优化GPU资源调度与智能管理