equals 与 ==
equals() 和 == 都用于比较,但比较的对象不同。本节详细介绍两者的区别和使用场景。
基本区别
| 对比项 | == | equals() |
|---|---|---|
| 比较内容 | 引用地址(内存) | 对象内容 |
| 基本类型 | 比较值 | 不适用 |
| 引用类型 | 比较引用 | 比较内容 |
| 可重写 | 否 | 是 |
基本类型比较
java
int a = 10;
int b = 10;
System.out.println(a == b); // true(比较值)
char c1 = 'A';
char c2 = 'A';
System.out.println(c1 == c2); // true(比较值)引用类型比较
== 比较引用
java
String s1 = new String("Hello");
String s2 = new String("Hello");
// == 比较引用地址
System.out.println(s1 == s2); // false(不同对象)equals() 比较内容
java
String s1 = new String("Hello");
String s2 = new String("Hello");
// equals() 比较内容(String 重写了 equals)
System.out.println(s1.equals(s2)); // true(内容相同)String 的特殊处理
字符串常量池
java
String s1 = "Hello"; // 字符串常量池
String s2 = "Hello"; // 复用 s1 的对象
String s3 = new String("Hello"); // 堆中创建新对象
System.out.println(s1 == s2); // true(常量池同一对象)
System.out.println(s1 == s3); // false(不同对象)
System.out.println(s1.equals(s3)); // true(内容相同)图解
┌─────────────────────────────────────────────────────────────────┐
│ 字符串比较 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 字符串常量池 │
│ ┌─────────┐ │
│ │ "Hello" │◀── s1 引用 │
│ │ │◀── s2 引用 │
│ └─────────┘ │
│ │
│ 堆内存 │
│ ┌─────────┐ │
│ │ "Hello" │◀── s3 引用 │
│ └─────────┘ │
│ │
│ s1 == s2 → true(常量池同一对象) │
│ s1 == s3 → false(堆中不同对象) │
│ s1.equals(s3) → true(内容相同) │
│ │
└─────────────────────────────────────────────────────────────────┘Object 的 equals 默认实现
java
public class Object {
public boolean equals(Object obj) {
return (this == obj); // 默认比较引用
}
}重写 equals 的要求
1. 自反性
java
x.equals(x) == true2. 对称性
java
x.equals(y) == y.equals(x)3. 传递性
java
if (x.equals(y) && y.equals(z)) {
x.equals(z) == true;
}4. 一致性
java
// 多次调用结果相同
x.equals(y) == x.equals(y)5. 非空性
java
x.equals(null) == false正确重写 equals
示例
java
public class User {
private String username;
private String email;
private int age;
@Override
public boolean equals(Object obj) {
// 1. 自反性
if (this == obj) {
return true;
}
// 2. 非空检查
if (obj == null || getClass() != obj.getClass()) {
return false;
}
// 3. 类型转换
User other = (User) obj;
// 4. 比较属性
return Objects.equals(username, other.username) &&
Objects.equals(email, other.email) &&
age == other.age;
}
@Override
public int hashCode() {
return Objects.hash(username, email, age);
}
}equals 与 hashCode 约定
java
// 如果 equals 返回 true,hashCode 必须相同
x.equals(y) == true → x.hashCode() == y.hashCode()
// 如果 hashCode 相同,equals 不一定返回 true
x.hashCode() == y.hashCode() ↛ x.equals(y) == true为什么需要这个约定
java
Map<User, Integer> map = new HashMap<>();
User user1 = new User("张三", 25);
map.put(user1, 1);
User user2 = new User("张三", 25);
// 如果不重写 hashCode,user2 可能找不到
System.out.println(map.get(user2)); // 可能返回 null常见问题
1. String 的 equals vs ==
java
String s1 = new String("Hello");
String s2 = new String("Hello");
// ❌ 使用 == 比较字符串
if (s1 == s2) {
// 永远不会执行
}
// ✅ 使用 equals 比较字符串
if (s1.equals(s2)) {
// 会执行
}2. 包装类的缓存
java
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(缓存范围内)
System.out.println(a.equals(b)); // true
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(超出缓存范围)
System.out.println(c.equals(d)); // true总结
==比较引用地址equals()默认比较引用,子类可重写比较内容- String 重写了 equals,比较内容
- 重写 equals 必须重写 hashCode
- 比较字符串使用 equals
