Skip to content

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) == true

2. 对称性

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

基于 VitePress 构建