杰瑞科技汇

Java中=与equals到底有啥本质区别?

核心摘要(一句话总结)

  • :是一个运算符,用于比较两个变量是否相等,对于基本数据类型,比较的是值本身;对于引用数据类型,比较的是它们所指向的内存地址是否相同。
  • equals():是一个方法(定义在Object类中),用于比较两个对象的是否逻辑上相等,它不比较内存地址,而是比较对象的状态(即成员变量的值)。

详细对比

特性 运算符 equals() 方法
本质 一个运算符 一个方法
比较对象 - 基本数据类型 (int, double, char等)
- 引用数据类型 (对象)
- 只能是对象(引用数据类型)
- 基本类型:比较是否相等。
- 引用类型:比较内存地址是否相同,即判断两个引用是否指向同一个对象实例。
默认情况下(从Object类继承),比较的是内存地址,与在引用类型上的行为相同,但通常,子类会重写此方法,以实现自定义的“内容相等”逻辑。
能否被重写 不能,是Java语言内置的运算符,其行为是固定的,无法被重写。 可以equals()方法在Object类中定义,任何类都可以(也应该)根据自身需求重写它。

代码示例与深入解析

让我们通过代码来直观地理解它们的区别。

Java中=与equals到底有啥本质区别?-图1
(图片来源网络,侵删)

的使用

a. 比较基本数据类型

对于基本数据类型,比较的是它们的值。

int a = 10;
int b = 10;
System.out.println(a == b); // 输出: true,因为a和b的值都是10
char c1 = 'A';
char c2 = 65; // 'A'的ASCII码就是65
System.out.println(c1 == c2); // 输出: true,因为字符'A'和整数65在值上是相等的

b. 比较引用数据类型

对于引用数据类型,比较的是它们在内存中的地址,只有两个引用指向同一个对象时,结果才为true

Java中=与equals到底有啥本质区别?-图2
(图片来源网络,侵删)
// 创建两个String对象
String s1 = new String("hello");
String s2 = new String("hello");
// s1和s2是两个不同的对象,内存地址不同
System.out.println(s1 == s2); // 输出: false
// s3和s4都指向字符串常量池中的"hello"(JVM优化后,可能指向同一地址)
// 但在大多数情况下,new String()都会创建新对象
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4); // 输出: true (因为JVM对字符串字面量做了优化,指向同一个常量池对象)
// 让s1指向s3引用的对象
s1 = s3;
System.out.println(s1 == s3); // 输出: true,因为现在s1和s3指向同一个内存地址

equals() 的使用

a. 默认行为(来自Object类)

如果没有重写equals()方法,它的行为和在引用类型上是一样的,比较的是内存地址。

class Person {
    String name;
    public Person(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        Person p3 = p1;
        // 默认的equals()比较内存地址
        System.out.println(p1.equals(p2)); // 输出: false (p1和p2是两个不同的对象)
        System.out.println(p1.equals(p3)); // 输出: true (p1和p3指向同一个对象)
    }
}

b. 重写equals()(以String类为例)

String类重写了equals()方法,使其比较的是字符串的,而不是内存地址,这是equals()最常见的用法。

Java中=与equals到底有啥本质区别?-图3
(图片来源网络,侵删)
String s1 = new String("hello");
String s2 = new String("hello");
// s1和s2的内存地址不同
System.out.println(s1 == s2); // 输出: false
// 但s1和s2的内容(字符串值)相同
System.out.println(s1.equals(s2)); // 输出: true

c. 重写equals()的最佳实践

当你自己创建一个类并希望比较对象内容时,应该遵循Object类中equals()方法的通用约定(在Effective Java一书中被强调):

  1. 自反性x.equals(x) 必须返回 true
  2. 对称性x.equals(y) 返回 truey.equals(x) 也必须返回 true
  3. 传递性x.equals(y) 返回 true,且 y.equals(z) 返回 truex.equals(z) 也必须返回 true
  4. 一致性:只要对象内容没有被修改,多次调用 x.equals(y) 的结果必须一致。
  5. 非空性x.equals(null) 必须返回 false

一个标准的重写equals()方法的模板如下:

@Override
public boolean equals(Object o) {
    // 1. 检查是否是同一个对象实例
    if (this == o) return true;
    // 2. 检查参数是否为null,以及是否是同一个类
    // 使用instanceof可以处理继承关系,更通用
    if (o == null || getClass() != o.getClass()) return false;
    // 3. 将对象进行类型转换
    Person person = (Person) o;
    // 4. 比较关键的字段,注意:基本类型用==,对象类型用equals
    // 最好先比较可能为null或性能开销大的字段
    return Objects.equals(name, person.name);
    // 如果有多个字段,可以继续添加 && Objects.equals(field1, o.field1) ...
}

注意:在重写equals()时,强烈建议同时重写hashCode()方法,这是因为如果一个对象被用作HashMapHashSet等哈希集合的键时,如果两个对象通过equals()比较是相等的,那么它们的hashCode()值也必须相等,否则,这些集合将无法正常工作。


总结与最佳实践

场景 推荐使用 原因
比较基本数据类型 是专门为此设计的,简单高效。equals不能用于基本类型。
比较两个对象是否为同一个实例(内存地址) 更直接,语义更清晰。
比较两个对象的内容(逻辑上是否相等) equals() 这是equals()方法的核心用途,如比较两个StringDate或自定义的业务对象是否“相等”。
将对象作为HashMapHashSet等集合的键 必须同时重写equals()hashCode() 这是集合框架正确工作的前提。

记忆口诀:

  • 基本类型用
  • 比用 equals()
  • 想比较是不是同一个东西,用
  • 想比较两个东西是不是长得一样(内容相同),用 equals()

希望这个详细的解释能帮助你彻底理解Java中和equals()的区别!

分享:
扫描分享到社交APP
上一篇
下一篇