Java equals方法揭秘:为何必须重写?

一、引言

           我们在编写Java实体类时,会使用构造器生成对应的有参的构造方法,无参的构造方法,以及set方法和get方法、equals方法和hashCode方法。那么我们来关注一下idea构造器生成的equals方法到底写了什么?而且为什么要写equals方法。

二、equals方法里面都写了什么?

       这里我们举例一下Student类,包含学号、姓名、年龄属性。

public class Student {
    private String studentId; // 学号
    private String name;
    private int age;
}

首先我们来看一下没重写的源码的equals方法包含了什么:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        return (anObject instanceof String aString)
                && (!COMPACT_STRINGS || this.coder == aString.coder)
                && StringLatin1.equals(value, aString.value);
    }
  1. if (this == anObject) { return true; }作用是快速判断是否是同一个引用,原理是如果this和传入的对象引用完全一致,那自然相等,无需比较,性能最优
  2. anObject instanceof String aString 则是判断对象是否是String类型.这是 Java 16+ 的增强语法,instanceof 同时完成类型判断 + 强制类型转换。
  3. (!COMPACT_STRINGS || this.coder == aString.coder)这是 Java 9 开始引入的新字符串优化机制 —— 紧凑字符串(Compact Strings) 的一部分。如果启用了紧凑字符串(COMPACT_STRINGS == true),并且两个字符串编码方式不同,就一定不相等 → 提前返回 false,避免不必要的逐字节比较。
  4. StringLatin1.equals(value, aString.value) 逐字节比较字符串内容是否一致。

我们使用idea生成重写之后的equals方法如下

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return Objects.equals(studentId, student.studentId);
}
  1. 第一个if判断的是this ==o ;这里作用是如果是同一个对象,直接返回True
  2. o == null 作用是被比较对象是一个null,则直接返回false;
  3. getClass()!=o.getClass() 作用是判断两个对象是否为同一类型。
  4. 接着下面强制类型转换,把object 类型转换为student类型。
  5. 最后的return 逐个比较核心字段值是否相同,通常使用 Objects.equals() 处理 null 安全

三、为什么要重写equals方法?&为什么要比较核心字段值是否相同?

首先从原理的角度来说,默认的equals方法比较的是地址值是否相同,这对很多业务场景并不适用。

其次,重写之后的equals方法比较的更加全面。目的是为了让对象根据内容判断是否相等,而不是引用。

为什么要比较核心字段值呢?

我们创建对象并进行比较,往往不是关心它们在内存中的地址是否一样(这是 == 的判断),而是关心:

“这两个对象在业务语义上是不是一样?”

这就必须依靠 核心字段值 来判断。

在业务中,我们常说:

  • 学号一样 → 就是同一个学生

那么这时你重写 equals() 时,就只需要比较 studentId,这是“核心字段”。

你可能感兴趣的:(java,intellij-idea,开发语言)