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

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。
示例:

// 创建两个 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() 方法,那么它和 的行为完全一样。
示例:

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 等类都重写了 |
何时使用 ?
- 比较基本数据类型:
int a = 5; if (a == 0) { ... } - 检查两个引用是否指向同一个对象:在需要判断对象唯一性或身份时。
何时使用 equals()?
- 比较对象的内容是否相等:这是最主要的使用场景,当你想知道两个对象在逻辑上是否“相同”时,应该使用
equals()。 - 比较字符串:永远使用
equals()来判断两个字符串的内容是否相同,有一个特例是,如果你想同时判断内容和地址(即它们是同一个字符串字面量),可以使用 ,但这通常不推荐,因为它依赖于JVM的内部实现。
记住这个黄金法则:
如果你想知道两个对象在逻辑上是否相等,请使用
equals()。 如果你想知道两个变量的值是否相等(对于基本类型)或它们是否指向同一个东西(对于引用类型),请使用 。
