判断对象逻辑相等需依集合类型选择判定机制:HashSet/HashMap依赖hashCode()与equals()协同,TreeSet/TreeMap依赖compareTo(),ArrayList/LinkedList按索引逐个equals();仅重写equals()不重写hashCode()会破坏哈希契约,导致重复插入或查找失败;正确做法是equals()与hashCode()保持一致,字段完全匹配,推荐用Objects.equals()和Objects.hash()保障null安全与一致性。

判断两个对象是否“逻辑相等”,不能只看它们长得像不像,关键得看用在哪——尤其在集合操作中,引用相等(==)和内容相等(equals())会触发完全不同的判定路径。一个没写对,HashSet里就存了两份“同一个用户”,HashMap里key就永远查不到。
集合内部怎么判断“是不是同一个元素”
不同集合依赖的判定机制根本不同:
-
HashSet / HashMap 的 key:先调
hashCode()算出桶位置,再对同桶内所有对象逐个调equals()比较。如果hashCode()不一致,equals()根本不会被执行 -
TreeSet / TreeMap:不看
hashCode()和equals(),而是依赖compareTo()或构造时传入的Comparator。两个对象是否“相等”,取决于比较结果是否为 0 -
ArrayList / LinkedList:按索引顺序严格比对,要求长度相同、每个位置的元素都
equals()成立。顺序错一位,结果就是false
为什么只重写 equals() 还是不行
常见错误是:写了 public boolean equals(Object o),但忘了配套重写 hashCode()。这会导致:
- 两个
id相同的User对象,equals()返回true,但hashCode()却算出不同值 - 它们被散列到 HashSet 的不同桶里,后续
contains()查不到,add()重复插入 - 放进 HashMap 当 key 后,
get()总返回null,哪怕那个 key 明明存在
核心契约只有一条:只要 equals() 返回 true,hashCode() 就必须返回相同整数。推荐统一用 Objects.hash(id) 生成,字段和 equals() 中参与比较的完全一致。
自定义类怎么写出安全的 equals() 和 hashCode()
以 Product 类为例,业务上认为 sku 相同即为同一商品:
- 第一步:用
this == obj快速判同一引用,避免空指针和多余计算 - 第二步:检查
obj == null || getClass() != obj.getClass(),类型不匹配直接false - 第三步:强转后,只比较
sku字段 —— 基本类型用==,引用类型用Objects.equals(sku, other.sku) -
hashCode()就用return Objects.hash(sku);,不多不少,不加name或price
数组、嵌套对象、null 安全怎么处理
标准 equals() 对数组无效(数组是对象,仍按地址比),必须用工具方法:
- 一维数组:
Arrays.equals(arr1, arr2) - 二维及以上:
Arrays.deepEquals(matrix1, matrix2) - 集合含自定义对象:
list1.equals(list2)能用,前提是每个元素的equals()都已正确实现 - 字段可能为
null?别手写a != null && a.equals(b),直接用Objects.equals(a, b),它内部已做空保护










