- :是一个运算符,用于比较两个变量引用的内存地址是否相同。
equals():是一个方法,用于比较两个对象内容(值)是否相同,但需要注意,它默认的行为也是比较内存地址,只有像String,Integer等包装类以及集合类重写了这个方法,才会比较内容。
运算符
是 Java 中的一个关系运算符,它的作用取决于它比较的两个变量的类型。

a) 比较基本数据类型 (Primitive Types)
当 用于比较两个基本数据类型(如 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) 比较引用数据类型 (Reference Types)
当 用于比较两个引用数据类型(如自定义的类、String、Integer 等)时,它会比较这两个引用是否指向同一个对象实例,也就是它们的内存地址是否相同。

示例:
class Person {
String name;
Person(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("张三");
Person p2 = new Person("张三");
Person p3 = p1;
System.out.println(p1 == p2); // 输出 false
System.out.println(p1 == p3); // 输出 true
}
}
分析:
p1 == p2:p1和p2是两个通过new关键字创建的新对象,它们在内存中占据不同的地址空间,p1 == p2返回false。p1 == p3:p3被赋值为p1的引用,这意味着p3和p1现在指向了完全相同的内存地址,它们是同一个对象的两个“名字”。p1 == p3返回true。
对于引用数据类型, 比较的是“地址是否相同”,即是否为同一个对象。
equals() 方法
equals() 是定义在 Object 类中的一个方法,这意味着所有的 Java 类(无论是 JDK 自带的还是我们自己创建的)都继承了这个方法。

a) Object 类中的 equals() 方法
让我们来看看 java.lang.Object 类中 equals() 方法的源码(简化版):
public boolean equals(Object obj) {
return (this == obj);
}
发现了吗? Object 类的 equals() 方法,其内部实现就是用 来比较的!如果你不重写 equals() 方法,那么对于任何对象,equals() 的效果和 是完全一样的,都是比较内存地址。
示例:
class Person {
String name;
Person(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("张三");
Person p2 = new Person("张三");
System.out.println(p1.equals(p2)); // 输出 false
}
}
分析:
因为我们没有在 Person 类中重写 equals() 方法,p1.equals(p2) 调用的是 Object 类的 equals() 方法,它实际上执行的是 p1 == p2,结果是 false。
b) 重写 equals() 方法
在实际开发中,我们更关心的是对象的内容(属性)是否相同,而不是它们是否是同一个内存实例,我们通常会重写 equals() 方法。
重写 equals() 的约定(来自 Object 类的文档):
- 自反性:
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)应该一致地返回true或false。 - 非空性:
x.equals(null)必须返回false。
示例:重写 Person 类的 equals() 方法
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写 equals 方法
@Override
public boolean equals(Object o) {
// 1. 检查是否是同一个对象实例
if (this == o) return true;
// 2. 检查参数是否为 null 或是否属于不同的类
if (o == null || getClass() != o.getClass()) return false;
// 3. 类型转换,将 Object 转换为当前类
Person person = (Person) o;
// 4. 比较类的属性
// 使用 Objects.equals 可以避免 NullPointerException
return age == person.age && java.util.Objects.equals(name, person.name);
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("张三", 25);
Person p2 = new Person("张三", 25);
Person p3 = new Person("李四", 25);
System.out.println(p1.equals(p2)); // 输出 true,因为 name 和 age 都相同
System.out.println(p1.equals(p3)); // 输出 false,因为 name 不同
}
}
分析:
p1.equals(p2) 会返回 true,因为我们重写了 equals() 方法,让它比较的是 name 和 age 这两个属性的内容,而不是内存地址。
String 类中的 equals() (一个重要的特例)
String 类是 Java 中最常用的类之一,它重写了 equals() 方法,专门用于比较字符串的内容是否相同。
示例:
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = s1;
System.out.println(s1 == s2); // 输出 false,因为 new 创建了两个不同的对象,地址不同
System.out.println(s1.equals(s2)); // 输出 true,因为 String 重写了 equals,比较的是内容 "hello"
System.out.println(s1 == s3); // 输出 true,因为 s3 指向 s1 的地址
System.out.println(s1.equals(s3)); // 输出 true
注意: 还有一个 String 类的方法叫做 equalsIgnoreCase(),它在比较时忽略大小写。
equals() 与 hashCode() 的关系
当你重写 equals() 方法时,必须同时重写 hashCode() 方法,这是一个非常重要的约定。
为什么?
因为很多 Java 集合类(特别是 HashMap, HashSet, Hashtable)都依赖于 hashCode() 来定位对象,这些集合的工作原理是:
- 计算对象的
hashCode(),确定它应该存储在哪个“桶”(bucket)里。 - 如果要查找一个对象,先计算它的
hashCode()找到对应的桶。 - 然后在桶内部,使用
equals()方法来精确比较,确认是否是我们要找的那个对象。
违反约定的后果:
如果你只重写了 equals() 而没有重写 hashCode(),那么两个内容相同的对象可能会被 HashMap 认为是不同的对象,导致它们被存储在不同的位置,从而破坏了集合的正确性。
最佳实践:
在重写 equals() 和 hashCode() 时,通常使用相同的属性来计算,在上面的 Person 类中,我们可以用 name 和 age 来生成 hashCode。
@Override
public int hashCode() {
return Objects.hash(name, age);
}
总结表格
| 特性 | 运算符 | equals() 方法 |
|---|---|---|
| 本质 | 运算符 | 方法 |
| - 基本类型:比较值 - 引用类型:比较内存地址 |
默认比较内存地址(继承自 Object),但可以被重写以比较 |
|
| 能否重写 | 不能 | 可以,且应该重写 |
String 类 |
s1 == s2 比较地址"a" == "a" (常量池) 可能比较地址 |
s1.equals(s2) 比较 |
| 与集合的关系 | 与集合类的内部逻辑无关 | HashSet, HashMap 等依赖 equals() 来判断对象是否重复 |
| 最佳实践 | - | 重写 equals() 时,必须同时重写 hashCode() |
希望这个详细的解释能帮助你彻底理解 和 equals() 的区别!
