杰瑞科技汇

Java中equals与=,区别到底在哪?

核心区别一句话总结

  • :是一个运算符,用于比较两个变量的值是否相等,对于基本数据类型,比较的是;对于引用数据类型,比较的是内存地址(引用)是否相同。
  • equals():是一个方法,用于比较两个对象的内容(逻辑上)是否相等,它的默认行为(来自 Object 类)和 一样,比较内存地址,但很多类(如 String, Integer 等)都重写了这个方法,以实现自定义的逻辑相等性判断。

运算符

的行为取决于它所比较的变量类型。

Java中equals与=,区别到底在哪?-图1
(图片来源网络,侵删)

a) 比较基本数据类型

当 用于比较两个基本数据类型(如 int, double, char 等)时,它会直接比较它们的是否相等。

示例:

int a = 10;
int b = 10;
int c = 20;
System.out.println(a == b); // 输出: true,因为 a 和 b 的值都是 10
System.out.println(a == c); // 输出: false,因为 a 的值是 10,c 的值是 20

b) 比较引用数据类型

当 用于比较两个引用数据类型(如 String, Object, Integer 等)时,它会比较这两个引用变量是否指向堆内存中的同一个对象,即它们的内存地址是否相同,如果两个引用指向同一个对象,返回 true;否则,返回 false

示例:

Java中equals与=,区别到底在哪?-图2
(图片来源网络,侵删)
// 创建两个 String 对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1; // s3 指向 s1 所指向的对象
System.out.println(s1 == s2); // 输出: false
// 解释:s1 和 s2 是两个通过 new 关键字创建的独立对象,它们在内存中的地址不同。
System.out.println(s1 == s3); // 输出: true
// 解释:s3 被赋值为 s1,所以它们指向的是堆内存中同一个 "hello" 对象,地址相同。

equals() 方法

equals() 是定义在 java.lang.Object 类中的方法,所有Java类都继承自 Object,因此所有对象都可以调用 equals() 方法。

a) Object 类中的 equals() 方法

Object 类中 equals() 方法的默认实现就是使用 来比较两个对象的内存地址。

// 源码(伪代码):
public boolean equals(Object obj) {
    return (this == obj);
}

这意味着,如果你不重写 equals() 方法,那么它和 的行为完全一样。

示例:

Java中equals与=,区别到底在哪?-图3
(图片来源网络,侵删)
class Person {
    String name;
    public Person(String name) {
        this.name = name;
    }
}
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
Person p3 = p1;
System.out.println(p1.equals(p2)); // 输出: false
// 解释:因为没有重写 equals(),所以默认使用 == 比较,p1 和 p2 是两个不同的对象,地址不同。
System.out.println(p1.equals(p3)); // 输出: true
// 解释:p1 和 p3 指向同一个对象,地址相同。

b) 重写后的 equals() 方法

很多Java类为了实现“逻辑相等性”而重写了 equals() 方法,它们会定义一套规则来判断两个对象在业务逻辑上是否“相等”,而不仅仅是内存地址是否相同。

最经典的例子就是 String 类。

String 类中的 equals() 方法: String 类重写了 equals(),它比较的是两个字符串对象的内容(即字符序列)是否完全相同,而不管它们是否是同一个对象。

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);      // 输出: false (地址不同)
System.out.println(s1.equals(s2));  // 输出: true (内容相同)

其他常见重写 equals() 的类:

  • Integer, Double 等包装类:比较的是它们包装的原始值是否相等。
  • ArrayList, HashSet 等集合类:通常比较集合中的元素是否相等。
  • 自定义类:强烈建议在你创建的类中重写 equals() 方法,以符合业务逻辑。

重要提示:当你重写 equals() 方法时,必须同时重写 hashCode() 方法,这是一个约定(来自 Object 类的文档),如果你不遵守,会导致在使用哈希集合(如 HashMap, HashSet)时出现无法预料的行为。


特殊情况:字符串字面量(String Pool

这是 和 equals() 比较时最容易混淆的地方。

在Java中,为了优化性能,JVM会维护一个字符串常量池,当你使用双引号 创建字符串时,JVM会先检查池中是否已存在该字符串,如果存在,就直接返回池中的引用;如果不存在,就在池中创建一个新的字符串,并返回其引用。

示例:

String s1 = "hello"; // JVM 在字符串常量池中查找 "hello",没找到,创建并返回引用
String s2 = "hello"; // JVM 在字符串常量池中查找 "hello",找到了,直接返回池中同一个引用
System.out.println(s1 == s2);         // 输出: true
System.out.println(s1.equals(s2));     // 输出: true
// 使用 new 关键字,则强制在堆内存中创建新对象,不经过字符串常量池
String s3 = new String("hello");
System.out.println(s1 == s3);         // 输出: false
System.out.println(s1.equals(s3));     // 输出: true

总结与最佳实践

特性 运算符 equals() 方法
本质 运算符 方法
比较对象 基本数据类型 或 引用数据类型 只能是对象
基本数据类型 比较变量的 不可用,会编译错误
引用数据类型 比较两个变量是否指向同一个对象(内存地址) 默认比较内存地址,但可被重写以比较内容(逻辑相等性)
默认行为 N/A 来自 Object 类,行为与 相同
常见重写 N/A String, Integer, ArrayList 等类都重写了

何时使用 ?

  1. 比较基本数据类型int a = 5; if (a == 0) { ... }
  2. 检查两个引用是否指向同一个对象:在需要判断对象唯一性或身份时。

何时使用 equals()

  1. 比较对象的内容是否相等:这是最主要的使用场景,当你想知道两个对象在逻辑上是否“相同”时,应该使用 equals()
  2. 比较字符串:永远使用 equals() 来判断两个字符串的内容是否相同,有一个特例是,如果你想同时判断内容和地址(即它们是同一个字符串字面量),可以使用 ,但这通常不推荐,因为它依赖于JVM的内部实现。

记住这个黄金法则:

如果你想知道两个对象逻辑上是否相等,请使用 equals()。 如果你想知道两个变量是否相等(对于基本类型)或它们是否指向同一个东西(对于引用类型),请使用 。

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