==和equals

tim-qtp...大约 2 分钟Java基础

①、==:用于比较两个对象的引用,即它们是否指向同一个对象实例。

对于基本数据类型(如 int, double, char 等),== 比较的是值是否相等。

②、equals() 方法:用于比较两个对象的内容是否相等。默认情况下,equals() 方法的行为与 == 相同,即比较对象引用,如在超类 Object 中:

public boolean equals(Object obj) {
    return (this == obj);
}

然而,equals() 方法通常被各种类重写。例如,String 类重写了 equals() 方法,以便它可以比较两个字符串的字符内容是否完全一样。

举个例子:

String a = new String("沉默王二");
String b = new String("沉默王二");

// 使用 == 比较
System.out.println(a == b); // 输出 false,因为 a 和 b 引用不同的对象

// 使用 equals() 比较
System.out.println(a.equals(b)); // 输出 true,因为 a 和 b 的内容相同

那为什么重写 equals 时必须重写 hashCode ⽅法?

因为只有两个对象通过 equals() 判断为相等时,返回相同的 hashCode() 值,这样才能在哈希表等数据结构中正确地存储和查找这些对象。

当我们重写 equals() 方法时,通常目的是让两个逻辑上相等的对象返回 true。例如,假设有个 Person 类,我们认为两个名字相同的人是相等的,即使它们不是同一个实例(内存地址不同):

public class Person {
    private String name;
    
    public Person(String name) {
        this.name = name;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person other = (Person) obj;
        return name.equals(other.name);
    }
    
    // 如果不重写 hashCode,就使用 Object 类的 hashCode,
    // 那么不同实例的 Person 对象会有不同的 hashCode,即使它们名字相同
}

在这个例子中,如果只重写了 equals() 而没有重写 hashCode(),那么虽然两个名字相同的 Person 对象 equals() 返回 true,但它们的 hashCode() 却可能不相同(因为默认的 hashCode() 是基于内存地址),而存入不同的桶中,这是不对的!

导致:

  • 查找失败:例如,在 HashSet 中用 contains() 查找时,会先通过 hashCode() 定位到桶,如果桶不相同,即使 equals() 返回 true,集合也找不到这个对象。
  • 重复存储:同样逻辑相等的对象可能会被认为是不同的,从而重复存储。