- :是一个运算符,用于比较两个变量的值是否相等,对于基本数据类型,比较的是值本身;对于引用数据类型,比较的是它们所指向的对象在内存中的地址(引用)是否相同。
equals():是一个方法,属于Object类,它的默认行为和 一样,也是比较两个对象的地址,很多类(如String,Integer等)会重写(Override)这个方法,使其用于比较对象的内容(值)是否相等。
下面我们来详细分解和对比。
运算符
是 Java 中最基本的关系运算符,它的行为取决于它所比较的数据类型。
比较基本数据类型
当 用于比较 int, double, char, boolean 等基本数据类型时,它会直接比较它们的值是否相等。
示例代码:
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
比较引用数据类型
当 用于比较对象(即引用数据类型)时,它比较的是这两个引用是否指向同一个内存地址,换句话说,它判断的是两个变量是否是同一个对象的“别名”。
示例代码:
// 创建两个 String 对象
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1; // s3 指向 s1 所指向的对象
// s1 和 s2 内容相同,但它们是两个不同的对象,内存地址不同
System.out.println(s1 == s2); // 输出: false
// s1 和 s3 指向同一个对象,内存地址相同
System.out.println(s1 == s3); // 输出: true
equals() 方法
equals() 是定义在 java.lang.Object 类中的一个方法,这意味着 Java 中的所有类都继承了这个方法。
Object 类中的 equals() (默认行为)
Object 类中 equals() 方法的源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
可以看到,默认的 equals() 方法实现和 是完全一样的,都是比较两个对象的内存地址。
重写后的 equals() (自定义行为)
虽然默认行为是比较地址,但在实际开发中,我们更关心的是对象的内容是否相同,Java 中的许多核心类都重写(Override)了 equals() 方法,以实现内容比较。
最经典的例子就是 String 类。
String 类中的 equals():
String 类重写了 equals() 方法,使其比较的是字符串的内容(字符序列)是否相同,而不管它们是否是同一个对象。
示例代码:
String s1 = new String("hello");
String s2 = new String("hello");
// s1 和 s2 是不同对象,s1 == s2 为 false
System.out.println(s1 == s2); // 输出: false
// 但 s1 和 s2 的内容相同,s1.equals(s2) 为 true
System.out.println(s1.equals(s2)); // 输出: true
其他重写了 equals() 的常见类:
Integer,Double等包装类:比较的是它们的数值。Date: 比较的是日期和时间是否相同。ArrayList等集合类:比较的是集合中的元素是否相同。
核心区别总结表
| 特性 | (运算符) | equals() (方法) |
|---|---|---|
| 本质 | 运算符 | Object 类的方法 |
| - 基本类型:比较值是否相等。 - 引用类型:比较内存地址(引用)是否相同。 |
- 默认行为:比较内存地址(与 相同)。 - 重写后:比较对象内容(值)是否相同(如 String)。 |
|
| 能否重写 | 不能,它是 Java 语言的一个固定运算符。 | 可以,任何类都可以重写此方法来定义自己的“相等”逻辑。 |
| 使用场景 | - 比较基本数据类型。 - 判断两个引用是否指向同一个对象。 |
- 比较两个对象的内容是否逻辑上相等,这是最常见和推荐的用法。 |
最佳实践与注意事项
何时使用 ?
- 永远使用 来比较基本数据类型(
int,boolean等)。 - 当你需要明确判断两个引用是否指向同一个对象实例时使用(单例模式检查、对象池管理等)。
何时使用 equals()?
- 当你想比较两个对象的内容是否相等时,请使用
equals(),这是 Java 面向对象编程中最常见的用法。 - 使用
equals()之前,务必先检查null,否则会抛出NullPointerException。
推荐的安全写法:
// 错误的写法,s1 可能是 null,会抛出异常
if (s1.equals("hello")) {
// ...
}
// 正确的写法(推荐)
if ("hello".equals(s1)) {
// ...
}
// 或者使用 Objects 工具类 (Java 7+)
if (Objects.equals(s1, "hello")) {
// ...
}
// Objects.equals() 内部已经处理了 null 的情况,非常安全。
一个重要的“陷阱”:equals() 与 hashCode() 的约定
如果你重写了 equals() 方法,强烈建议你同时重写 hashCode() 方法,这是一个非常重要的约定,如果不遵守,会导致一些严重的问题,特别是在使用哈希集合(如 HashMap, HashSet, Hashtable)时。
**
a.equals(b)返回true,a.hashCode()必须和b.hashCode()相等。a.equals(b)返回false,a.hashCode()和b.hashCode()可以相同,也可以不同(但最好不同,以提高哈希表的性能)。
违反约定的后果:
如果你把两个内容相等(equals() 为 true)但 hashCode() 不同的对象放入 HashSet,它们会被视为两个不同的元素,从而破坏了集合的唯一性原则。
记住这个核心思想:
- 比较的是“身份”:两个东西是不是同一个东西(内存地址)。
equals()比较的是“内容”:两个东西看起来是不是一样(值),前提是这个类重写了equals()方法。
在编写 Java 代码时,如果你不确定一个类是否重写了 equals(),但又想比较内容,最好的做法是查看该类的 API 文档,对于所有你自己创建的类,如果你希望它们的内容可以被比较,就应该遵循规范,重写 equals() 和 hashCode() 方法。
