前言
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:https://www.captainbed.cn/z
文章目录
以下是专栏第一篇的完整文章内容,按照要求包含错误场景复现、原理分析、修复方案和代码对比:
== 与 equals 的陷阱:对象比较为何总出错?
1. 错误场景复现
场景1:字符串比较的迷惑行为
String s1 = "Java";
String s2 = new String("Java");
String s3 = s2;
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
System.out.println(s2 == s3); // true
初级开发者常误用 ==
比较字符串内容,而实际上 ==
比较的是对象内存地址,而非字符串值。
场景2:自定义对象比较失效
class User {
private Long id;
private String name;
// 未重写 equals() 方法
}
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
System.out.println(user1.equals(user2)); // false(默认调用Object类的equals,等同于==)
即使两个对象业务逻辑上“相等”,未正确重写 equals()
方法仍会导致比较失败。
2. 原理解析
== 的本质
- 对基本类型(
int
,double
等):直接比较值是否相等 - 对引用类型(对象):比较堆内存地址是否相同(即是否为同一个对象)
equals() 的默认行为
Object
类的默认实现:return (this == obj);
- 若需按业务规则比较对象,必须重写
equals()
方法。
3. 正确解决方案
正确重写 equals() 的步骤
@Override
public boolean equals(Object o) {
// 1. 自反性:检查是否与自己比较
if (this == o) return true;
// 2. 类型检查:null和非同类对象直接返回false
if (o == null || getClass() != o.getClass()) return false;
// 3. 类型转换
User user = (User) o;
// 4. 按业务逻辑比较关键字段
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name);
}
// 必须同时重写 hashCode()!
@Override
public int hashCode() {
return Objects.hash(id, name);
}
为什么必须重写 hashCode()?
- 哈希集合(如HashMap/HashSet)依赖此方法:若两个对象
equals()
为true
,但hashCode()
不同,会导致集合行为异常。 - 示例:将两个“相等”对象存入
HashSet
,会错误地存储为两个独立元素。
4. 工具与最佳实践
避免手写错误的技巧
- 使用IDE自动生成(IntelliJ:
Alt + Insert
→equals() and hashCode()
) - Lombok简化代码:添加
@EqualsAndHashCode
注解自动生成 - Guava工具类:
Objects.equal(a, b)
安全比较对象
Code Review检查清单
检查项 | 正确做法 |
---|---|
比较对象是否使用 equals() ? | 引用类型永远用 equals() ,基本类型用 == |
重写 equals() 时是否重写 hashCode() ? | 必须同时重写,否则破坏哈希集合契约 |
是否处理了 null 和类型检查? | 避免 ClassCastException 和 NullPointerException |
5. 真实案例
某电商平台因未重写 Order
类的 equals()
,导致促销系统错误判断重复订单。
后果:用户利用漏洞重复领取优惠券,造成数十万元损失。
修复:重写 equals()
和 hashCode()
,比较订单ID和用户ID字段。
总结
==
是“物理相等”,equals()
是“逻辑相等”- 重写
equals()
必须同时重写hashCode()
- 使用工具自动生成代码,避免低级错误
下期预告:《常见的空指针异常(NullPointerException)及预防方法》——如何用Optional和防御性编程让代码“坚如磐石”。
希望这篇内容能帮助初级开发者彻底理解对象比较的核心机制,建议结合代码实操加深记忆。
联系作者
职场经验分享,Java面试,简历修改,求职辅导尽在科技泡泡
思维导图面试视频合集