核心摘要(一句话总结)
- :是一个运算符,用于比较两个变量的值是否相等,对于基本数据类型,比较的是值本身;对于引用数据类型,比较的是它们所指向的内存地址是否相同。
equals():是一个方法(定义在Object类中),用于比较两个对象的是否逻辑上相等,它不比较内存地址,而是比较对象的状态(即成员变量的值)。
详细对比
| 特性 | 运算符 | equals() 方法 |
|---|---|---|
| 本质 | 一个运算符 | 一个方法 |
| 比较对象 | - 基本数据类型 (int, double, char等) - 引用数据类型 (对象) |
- 只能是对象(引用数据类型) |
| - 基本类型:比较值是否相等。 - 引用类型:比较内存地址是否相同,即判断两个引用是否指向同一个对象实例。 |
默认情况下(从Object类继承),比较的是内存地址,与在引用类型上的行为相同,但通常,子类会重写此方法,以实现自定义的“内容相等”逻辑。 |
|
| 能否被重写 | 不能,是Java语言内置的运算符,其行为是固定的,无法被重写。 | 可以。equals()方法在Object类中定义,任何类都可以(也应该)根据自身需求重写它。 |
代码示例与深入解析
让我们通过代码来直观地理解它们的区别。

(图片来源网络,侵删)
的使用
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。

(图片来源网络,侵删)
// 创建两个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()最常见的用法。

(图片来源网络,侵删)
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一书中被强调):
- 自反性:
x.equals(x)必须返回true。 - 对称性:
x.equals(y)返回true,y.equals(x)也必须返回true。 - 传递性:
x.equals(y)返回true,且y.equals(z)返回true,x.equals(z)也必须返回true。 - 一致性:只要对象内容没有被修改,多次调用
x.equals(y)的结果必须一致。 - 非空性:
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()方法,这是因为如果一个对象被用作HashMap或HashSet等哈希集合的键时,如果两个对象通过equals()比较是相等的,那么它们的hashCode()值也必须相等,否则,这些集合将无法正常工作。
总结与最佳实践
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 比较基本数据类型 | 是专门为此设计的,简单高效。equals不能用于基本类型。 |
|
| 比较两个对象是否为同一个实例(内存地址) | 更直接,语义更清晰。 | |
| 比较两个对象的内容(逻辑上是否相等) | equals() |
这是equals()方法的核心用途,如比较两个String、Date或自定义的业务对象是否“相等”。 |
将对象作为HashMap、HashSet等集合的键 |
必须同时重写equals()和hashCode() |
这是集合框架正确工作的前提。 |
记忆口诀:
- 基本类型用 。
- 比用
equals()。 - 想比较是不是同一个东西,用 。
- 想比较两个东西是不是长得一样(内容相同),用
equals()。
希望这个详细的解释能帮助你彻底理解Java中和equals()的区别!
