核心区别一句话总结
- :是一个运算符,用于比较两个变量的值是否相等,对于基本数据类型,比较的是“数值”;对于引用数据类型,比较的是“内存地址”(即是否指向同一个对象)。
equals():是一个方法(在Object类中定义),用于比较两个对象”或“逻辑值”是否相等,默认情况下,它和 的行为一样(比较内存地址),但很多类(如String,Integer)都重写(Override)了这个方法,以实现自定义的“内容相等”逻辑。
详细对比表格
| 特性 | 运算符 | equals() 方法 |
|---|---|---|
| 本质 | 运算符 | Object 类中定义的方法 |
| 作用对象 | - 基本数据类型 (int, double, char 等) - 引用数据类型 (对象) |
只能用于对象 |
| - 基本类型:比较数值是否相等。 - 引用类型:比较两个对象的内存地址是否相同(即是否为同一个对象实例)。 |
默认情况下(Object 类中的实现),比较两个对象的内存地址是否相同。但,子类通常会重写此方法,以比较对象的或状态是否逻辑相等。 |
|
| 能否被重写 | 不能。 是 Java 语言的一个固定运算符,其行为是固定的。 | 可以,强烈建议子类根据业务需求重写此方法。 |
| 示例 | int a = 5; int b = 5; a == b; // 结果为 trueString s1 = new String("hello"); String s2 = new String("hello"); s1 == s2; // 结果为 false |
String s1 = new String("hello"); String s2 = new String("hello"); s1.equals(s2); // 结果为 true |
| 使用场景 | - 比较基本类型变量(首选)。 - 快速判断两个引用变量是否指向同一个对象(性能高)。 |
- 需要比较两个对象的内容是否逻辑相等时(比较两个 User 对象的用户名和密码是否相同)。- 永远不要用 来比较字符串! |
代码示例与深入解释
基本数据类型
对于基本数据类型, 比较的是它们的值。

int x = 10; int y = 10; int z = 20; System.out.println(x == y); // 输出: true,因为 x 和 y 的值都是 10 System.out.println(x == z); // 输出: false,因为 x 的值是 10,z 的值是 20
equals() 方法不能用于基本数据类型,因为它们不是对象,如果你尝试对一个基本类型变量调用 equals(),会编译错误。
引用数据类型(对象)
这是最容易混淆的地方,我们以 String 为例。
比较内存地址
// s1 和 s2 是两个通过 new 关键字创建的独立对象
// 它们在内存中的地址是不同的
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // 输出: false
// 解释:s1 和 s2 是两个不同的对象实例,内存地址不同。
equals() 比较内容(因为 String 重写了 equals)
String 类重写了 Object 类中的 equals() 方法,使其比较的是字符串的字符序列内容,而不是内存地址。
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1.equals(s2)); // 输出: true
// 解释:s1 和 s2 的内容都是 "hello",equals() 返回 true。
一个重要的特例:字符串字面量
Java 为了优化性能,会字符串常量池,当你使用双引号 创建字符串时,JVM 会先检查池中是否已存在该字符串,如果存在,就直接引用;如果不存在,就创建并放入池中。

// "hello" 是字符串字面量 // JVM 只会在池中创建一个 "hello" 对象 String s1 = "hello"; String s2 = "hello"; // s1 和 s2 指向池中同一个 "hello" 对象 System.out.println(s1 == s2); // 输出: true (内存地址相同) System.out.println(s1.equals(s2)); // 输出: true (内容也相同)
自定义类中的 equals()(非常重要)
如果你创建自己的类,并且希望比较两个实例的内容(而不是地址),你必须重写 equals() 方法,为了遵循 Java 规范,最好也重写 hashCode() 方法(否则在使用哈希集合如 HashMap、HashSet 时会出现问题)。
不重写 equals() 的情况(默认行为):
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
// 没有重写 equals() 方法
}
public class Test {
public static void main(String[] args) {
User user1 = new User("Alice", 30);
User user2 = new User("Alice", 30);
System.out.println(user1 == user2); // 输出: false,因为它们是两个不同的对象
System.out.println(user1.equals(user2)); // 输出: false,因为 User 类没有重写 equals(),它使用 Object 类的默认实现(比较内存地址)
}
}
重写 equals() 方法的情况(自定义内容比较):
import java.util.Objects;
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
// IDE(如 IntelliJ IDEA 或 Eclipse)可以自动生成这个方法
@Override
public boolean equals(Object o) {
// 1. 检查是否是同一个对象实例
if (this == o) return true;
// 2. 检查参数是否为 null 或是否属于不同的类
if (o == null || getClass() != o.getClass()) return false;
// 3. 类型转换
User user = (User) o;
// 4. 比较所有关键属性
return age == user.age && Objects.equals(name, user.name);
}
// 重写 equals() 后,必须重写 hashCode(),这是一个约定
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test {
public static void main(String[] args) {
User user1 = new User("Alice", 30);
User user2 = new User("Alice", 30);
System.out.println(user1 == user2); // 输出: false
System.out.println(user1.equals(user2)); // 输出: true,因为现在比较的是 name 和 age 的值
}
}
总结与最佳实践
- 基本类型用 :永远用 来比较
int,double,char等基本数据类型。 - 对象比较内容用
equals():当你想知道两个对象在逻辑上是否“相等”(两个User对象代表的是同一个人)时,使用equals()。 - 对象比较地址用 :当你需要确认两个引用变量是否指向完全相同的对象实例时(单例模式检查),使用 。
- 永远不要用 比较字符串:除非你明确想检查两个字符串变量是否指向池中同一个字面量,对于业务逻辑,99% 的情况都应该用
equals()。 - 重写
equals()就要重写hashCode():这是 Java 集合框架(特别是哈希表)的硬性要求,可以避免HashMap等集合出现异常行为。

