在 Java 中,==、equals() 和 hashCode() 是用于对象比较和哈希管理的核心机制,但它们的作用和适用场景有本质区别。以下是它们的详细说明和对比:
一. == 操作符
作用
- 基本数据类型:比较两个变量的
值
是否相等 - 对象引用:比较两个对象的
内存地址
是否相同(即是否指向同一个对象)
特点
- 不可重写
- 直接基于底层内存或值进行比较
示例
int a = 10;
int b = 10;
System.out.println(a == b); // true(基本类型比较值)
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false(对象引用比较内存地址)
二. equals() 方法
作用
- 默认行为:与
==
相同,比较对象的内存地址 - 可重写:通过重写该方法,可以自定义对象
逻辑内容
的相等性
示例
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1.equals(s2)); // true(String类重写了equals,比较内容)
class Person {
String name;
int age;
// 未重写equals,默认比较地址
}
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println(p1.equals(p2)); // false(未重写equals)
重写规则
- 自反性:a.equals(a) 必须为 true
- 对称性:若 a.equals(b) 为 true,则 b.equals(a) 必须为 true
- 传递性:若 a.equals(b) 且 b.equals(d),则 a.equals(d)
- 一致性:多次调用结果一致(除非对象被修改)
- 非空性:a.equals(null) 必须返回 false
@Override
public boolean equals(Object o) {
if (this == o) return true; // 同一对象直接返回true
if (o == null || getClass() != o.getClass()) return false; // 类型不同返回false
Person person = (Person) o; // 类型转换
return age == person.age && Objects.equals(name, person.name); // 比较字段值
}
三. hashCode() 方法
作用
- 返回对象的
哈希码
(一个整数),用于哈希表(如 HashMap、HashSet)中快速定位数据 - 默认实现返回对象内存地址的哈希码,但可被重写
规则
一致性
:若 a.equals(b) 为 true,则 a.hashCode() == b.hashCode() 必须成立非强制唯一性
:不同对象的哈希码可以相同(哈希冲突),但应尽量均匀分布
@Override
public int hashCode() {
return Objects.hash(name, age); // 基于字段生成哈希码
}
四. 三者的区别与联系
特性 | == | equals() | hashCode() |
---|---|---|---|
比较内容 | 内存地址(对象)或值(基本类型) | 逻辑内容(需重写后生效) | 哈希码(整数) |
默认行为 | 比较地址或值 | 比较地址(默认与 == 相同) | 返回内存地址的哈希码 |
重写可能性 | 不可重写 | 可重写(如 String、Integer) | 需与 equals() 一致时重写 |
主要用途 | 判断对象是否同一实例 | 判断对象内容是否逻辑相等 | 哈希表快速定位数据 |
五. 核心关系
(1) equals() 与 hashCode() 的强制约定
- 规则:若 a.equals(b) 为 true,则 a.hashCode() == b.hashCode() 必须成立
- 反例:若违反此规则,哈希表(如 HashMap)可能无法正确工作
// 错误示例:重写equals但未重写hashCode
class Person {
String name;
@Override
public boolean equals(Object o) { /* 比较name */ }
// 未重写hashCode
}
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
System.out.println(p1.equals(p2)); // true
System.out.println(p1.hashCode() == p2.hashCode()); // false(违反规则)
(2) == 与 equals() 的对比
- 基本类型:只能用 ==
- 对象引用:
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false(地址不同)
System.out.println(s1.equals(s2)); // true(内容相同)
六. 示例:完整重写
class Person {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
实践注意点:
- 始终同时重写 equals() 和 hashCode() 确保哈希表操作的正确性。
- 使用 IDE 或工具类生成代码 如 Objects.equals() 和 Objects.hash()。
- 避免用 == 比较对象内容 除非明确需要地址比较。
- 利用 @Override 注解 防止重写方法时的拼写错误。
七.总结
- ==:用于基本类型值比较或对象地址比较。
- equals():定义对象的逻辑相等性(需重写)。
- hashCode():支持哈希表操作,必须与 equals() 一致。
- 三者协作:确保对象在逻辑比较和哈希存储中行为一致。