一、本质区别
比较方式 | 作用原理 | 比较内容 | 适用场景 |
---|---|---|---|
== | 比较内存地址(引用比较) | 对象在堆中的物理地址 | 基本类型和对象引用比较 |
equals | 比较逻辑内容(内容比较) | 对象实际存储的数据值 | 对象内容的语义相等判断 |
二、具体使用场景
1. 基本数据类型比较
int a = 5;
int b = 5;
System.out.println(a == b); // true(值比较)
// 基本类型没有equals方法
2. 对象比较
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(不同内存地址)
System.out.println(s1.equals(s2)); // true(内容相同)
3. 字符串常量池特例
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4); // true(指向字符串常量池同一对象)
System.out.println(s3.equals(s4)); // true
三、equals
方法规范
1. 正确实现equals的五大原则
-
自反性:
x.equals(x)
必须返回true -
对称性:
x.equals(y)
与y.equals(x)
结果相同 -
传递性:如果
x.equals(y)
且y.equals(z)
,则x.equals(z)
-
一致性:多次调用结果不变(不依赖可变字段)
-
非空性:
x.equals(null)
必须返回false
2. 典型equals实现
@Override
public boolean equals(Object o) {
// 1. 地址相同
if (this == o) return true;
// 2. 类型检查
if (o == null || getClass() != o.getClass()) return false;
// 3. 字段比较
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
四、特殊案例解析
1. Integer缓存问题
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); // true(使用缓存)
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); // false(超出缓存范围)
2. BigDecimal比较
BigDecimal d1 = new BigDecimal("2.0");
BigDecimal d2 = new BigDecimal("2.00");
System.out.println(d1.equals(d2)); // false(精度不同)
System.out.println(d1.compareTo(d2) == 0); // true(值相同)
五、深度问题
Q1:为什么重写equals必须重写hashCode?
A:违反hashCode
契约会导致哈希集合异常:
Map<Person, String> map = new HashMap<>();
map.put(new Person("Alice", 20), "CEO");
// 如果只重写equals不重写hashCode,这里会返回null
System.out.println(map.get(new Person("Alice", 20)));
Q2:String的equals实现原理?
A:JDK源码实现:
public boolean equals(Object anObject) {
if (this == anObject) return true;
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Q3:如何比较两个数组内容?
A:使用Arrays.equals()
:
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
System.out.println(arr1 == arr2); // false
System.out.println(Arrays.equals(arr1, arr2)); // true
Q4:==比较对象时,比较的是hashCode吗?
A:不是!==
比较的是对象地址(内存物理位置),与hashCode()
无关。默认的hashCode()
实现通常与地址相关,但可能被重写。
六、最佳实践
-
基本类型:总是使用
==
-
对象比较:
-
需要内容比较时:重写
equals
+hashCode
-
需要同一性检查时:使用
==
-
-
字符串比较:
-
常量比较:
"literal".equals(var)
(避免NPE) -
变量比较:
Objects.equals(str1, str2)
(Java7+)
-
-
工具类使用:
-
Objects.equals(a, b)
(处理null安全) -
Arrays.equals()
比较数组内容
-