这个案例能帮你搞懂Java中equals和=的区别吗

wen java案例 51

本文目录导读:

这个案例能帮你搞懂Java中equals和=的区别吗

  1. 案例代码
  2. 运行结果
  3. 关键图解 (以 new String() 为例)
  4. 几点补充说明

这是一个非常经典的 Java 面试题,也是初学者容易混淆的核心概念,用一个具体的案例来解释,确实是最直观的方式。

我们先直接看案例,然后再总结原理。

案例代码

public class EqualsAndDoubleEqual {
    public static void main(String[] args) {
        // ---------- 场景 1: 基本数据类型 ----------
        int a = 10;
        int b = 10;
        System.out.println("基本类型 int 比较: " + (a == b)); 
        // 输出: true (比较值)
        // ---------- 场景 2: 引用类型 - 字符串字面量 ----------
        String s1 = "hello";
        String s2 = "hello";
        System.out.println("字符串字面量 == 比较: " + (s1 == s2)); 
        // 输出: true (因为字符串常量池,s1和s2指向同一个对象)
        System.out.println("字符串字面量 equals 比较: " + s1.equals(s2)); 
        // 输出: true (比较内容)
        // ---------- 场景 3: 引用类型 - new 创建的不同字符串对象 ----------
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println("new String == 比较: " + (s3 == s4)); 
        // 输出: false (s3和s4是堆中两个不同的对象,内存地址不同)
        System.out.println("new String equals 比较: " + s3.equals(s4)); 
        // 输出: true (String的equals方法被重写,比较的是字符内容)
        // ---------- 场景 4: 引用类型 - 自定义类 (未重写equals) ----------
        Person p1 = new Person("张三", 20);
        Person p2 = new Person("张三", 20);
        System.out.println("自定义类 == 比较: " + (p1 == p2)); 
        // 输出: false (两个不同对象,地址不同)
        System.out.println("自定义类 equals 比较 (未重写): " + p1.equals(p2)); 
        // 输出: false (Object的equals默认也是比较地址,所以为false)
        // ---------- 场景 5: 引用类型 - 自定义类 (重写equals) ----------
        PersonWithEquals p3 = new PersonWithEquals("李四", 25);
        PersonWithEquals p4 = new PersonWithEquals("李四", 25);
        System.out.println("重写equals类 == 比较: " + (p3 == p4)); 
        // 输出: false (依然是两个不同对象)
        System.out.println("重写equals类 equals 比较: " + p3.equals(p4)); 
        // 输出: true (我们重写了equals,比较的是name和age的内容)
    }
}
// 辅助类1:没有重写equals
class Person {
    String name;
    int age;
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
// 辅助类2:重写了equals
class PersonWithEquals {
    String name;
    int age;
    PersonWithEquals(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true; // 如果指向同一个对象,直接返回true
        if (obj == null || getClass() != obj.getClass()) return false;
        PersonWithEquals that = (PersonWithEquals) obj;
        return age == that.age && name.equals(that.name); // 比较核心属性
    }
}

运行结果

基本类型 int 比较: true
字符串字面量 == 比较: true
字符串字面量 equals 比较: true
new String == 比较: false
new String equals 比较: true
自定义类 == 比较: false
自定义类 equals 比较 (未重写): false
重写equals类 == 比较: false
重写equals类 equals 比较: true

比较方面 (双等号) .equals()
适用于基本类型 比较的是数值是否相等 ❌ 不能用于基本类型
适用于引用类型 比较的是内存地址 (是否指向同一个对象) 默认比较地址,但通常重写后比较内容
String类的默认行为 比较地址 (但字面量复用常量池) 已重写,比较字符串内容
是否可自定义 不能 (Java语法固定) 可以 (在自定义类中重写该方法,实现自己的比较逻辑)

关键图解 (以 new String() 为例)

内存堆:
  s3 ------> [ 字符串对象 "hello" ]  (地址 0x100)
  s4 ------> [ 字符串对象 "hello" ]  (地址 0x200)
  s3 == s4      => false  (因为 0x100 != 0x200,比较的是地址)
  s3.equals(s4) => true   (因为 String的equals方法会逐字符对比: 'h'='h', 'e'='e', ...)

几点补充说明

  1. 基本类型没有 equals 方法int a = 10; a.equals(b); 这种写法会编译报错。
  2. String 的 有时为 true:就像案例中的 s1 == s2,这是因为 JVM 的字符串常量池机制,直接用双引号 "hello" 创建的字符串,JVM 会先在常量池查找,如果已有就直接复用,s1s2 指向的是同一个对象, 返回 true,但 new String("hello") 一定会创建新对象, 返回 false。
  3. 重写 equals 必须重写 hashCode:这是 Java 的约定。p3.equals(p4) 返回 true,那么它们的 hashCode() 也应该相同,否则在 HashMapHashSet 等集合中会出现逻辑错误,IDE (如 IDEA, Eclipse) 可以自动生成这两个方法。

简单一句话概括:

  • 比的是“是不是同一个人” (地址/值)。
  • equals (重写后) 比的是“人身上的内容是不是一样” (属性内容)。

抱歉,评论功能暂时关闭!