Java equals() 和 hashCode() 详解
2025/12/2大约 3 分钟
📝 Java 核心:==、equals() 和 hashCode() 笔记
一、== 和 equals() 的区别
1. == 运算符
== 运算符用于比较:
- 基本数据类型 (Primitive Types):比较的是值。
- 引用类型 (Reference Types):比较的是内存地址,即是否指向同一个对象。
== 示例:
// 1. 基本数据类型比较(比较值)
int a = 5;
int b = 5;
System.out.println(a == b); // true, 比较值
// 2. 引用类型比较(比较内存地址)
class Person {
String name;
Person(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
System.out.println(p1 == p2); // false, 引用地址不同 (p1 和 p2 是两个不同的对象)
}
}2. equals() 方法
equals() 方法定义在 Object 类中,默认的实现就是使用 == 比较:
public boolean equals(Object obj) {
return (this == obj); // 默认比较的是内存地址
}但是,equals() 方法通常会被重写 (Override),以实现逻辑相等的概念(比较对象的内容/字段)。
String 类重写 equals() 示例:
String 类重写了 equals() 方法,用于比较字符串的内容是否相等。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
// ... 省略比较字符串内容的逻辑 ...
// 核心逻辑是逐个字符比较两个 String 对象的 char[] value 数组
// ...
return true; // 如果内容一致则返回 true
}
return false;
}二、hashCode() 详解
1. 什么是 hashCode()?
hashCode()是Object类的一个native方法。- 它返回一个
int类型的哈希值。 - 它主要用于基于哈希表的数据结构(如
HashMap、HashSet等)中。
2. 为什么要有 hashCode()?
- 提高哈希表性能: 哈希表使用
hashCode()快速定位元素,比直接使用equals()遍历查找效率高得多。 - 快速比较: 可以先比较两个对象的哈希值。如果
hashCode()值不同,则对象肯定不同,无需再调用equals()进行比较。
3. hashCode() 的通用约定(核心)
在 Java 中,当重写 equals() 方法时,必须同时重写 hashCode() 方法。这是一条重要的约定:
- 一致性: 在一次 Java 应用程序执行期间,只要对象中参与哈希计算的字段没有被修改,对同一个对象多次调用
hashCode()方法,必须返回相同的整数。 - 相等对象哈希值必须相等: 如果两个对象根据
equals()方法是相等的,那么它们的hashCode()返回值也必须相等。 - 不等对象哈希值不一定不等: 反过来,即使两个对象的
hashCode()相等,它们也不一定是相等的对象(可能存在哈希冲突)。
4. 重写 equals() 而不重写 hashCode() 的问题
如果只重写了 equals() 方法,而没有重写 hashCode() 方法,当对象用在基于哈希的集合中(如 HashMap、HashSet)时,就会出现异常行为:
假设 Person 类只重写了 equals():
public class Person {
private String name;
private int age;
// ... 构造函数 ...
@Override
public boolean equals(Object obj) {
// ... 实现内容相等比较,例如 name 和 age 都相等 ...
}
// !! 缺少重写 hashCode() 方法 !!
}如果两个 Person 对象 p1 和 p2 内容相等(即 p1.equals(p2) 为 true),但由于没有重写 hashCode(),它们会继承 Object 默认的 hashCode(),返回不同的内存地址哈希值。
当将 p1 存入 HashSet 或作为 HashMap 的键时,p1 和 p2 将被视为两个不相同的对象,导致无法正确地进行查找和去重操作,违背了 Java 对象模型的约定。
