在Java里集合中对象相等性如何判断_Javaequals与hashCode解析
发布时间 - 2026-01-23 00:00:00 点击率:次是的。equals()不重写时默认用==比较内存地址,导致逻辑相等的对象被视为不等;必须同时重写hashCode()以保证哈希集合正确查找,且二者参与比较的字段须严格一致。
equals() 方法不重写就等于 == 吗?
是的。Java 中所有类默认继承自 Object,其 equals() 方法底层就是用 == 比较两个引用是否指向同一内存地址。这意味着:即使两个 Person 对象字段值完全相同,只要不是同一个实例,equals() 就返回 false。
常见错误现象:
- 往
HashSet或HashMap里添加自定义对象后查不到 —— 因为没重写equals()和hashCode() -
list.contains(new Person("Alice", 25))总是返回false,哪怕列表里已有相同字段的对象
实操建议:
- 只要类会被用于集合查找、去重、作为
Map键,就必须重写equals() - 重写时只比较业务上“逻辑相等”的字段(比如
id或username),不要包含可变字段(如lastLoginTime) - 务必先用
==判断是否为同一引用,再判null,最后用Objects.equals()比较字段 —— 避免 NPE
为什么重写了 equals() 还必须重写 hashCode()?
因为哈希集合(HashSet、HashMap 的 key)依赖 hashCode() 快速定位桶位置。如果两个对象 equals() 返回 true,但 hashCode() 不同,它们会被散列到不同桶中,导致“明明存在却查不到”。
违反约定的后果:
-
HashSet.add(obj)可能重复添加逻辑相等的对象 -
map.get(key)返回null,即使该key已存在 - JVM 不报错,但行为不可预测 —— 这是最难调试的一类 bug
实操建议:
- 用
Objects.hash(field1, field2, ...)生成hashCode(),它自动处理null - 参与
hashCode()计算的字段,必须和equals()中比较的字段严格一致 - 避免在
hashCode()中使用可变字段(如普通 setter 修改的属性),否则对象加入集合后修改字段会导致哈希码变化,再也找不回来
IDE 自动生成的 equals/hashCode 安全吗?
IntelliJ / Eclipse 生成的代码基本可用,但有三个关键点容易被忽略:
- 默认会把所有非静态字段都纳入比较和哈希计算 —— 如果类里有
transient字段、缓存字段或懒加载代理(如 Hibernate 的LazyInitializationException相关字段),必须手动剔除 - 若字段是集合(如
List),生成的Objects.equals()调用是安全的;但若字段是自定义对象,且该对象没重写equals(),整个链路仍会失效 - 生成的
hashCode()使用Objects.hash()是对的,但要注意:如果字段本身重写了hashCode(),要确认其实现是否稳定(比如是否依赖运行时状态)
示例:一个典型的安全重写片段
public class User {
private final String username;
private final int age;
private transient String cacheToken; // 不参与 equals/hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() 
!= o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(username, user.username);
}
@Override
public int hashCode() {
return Objects.hash(username, age); // 不含 cacheToken
}
}
String、Integer 等包装类为什么可以直接用?
因为 JDK 已经为它们正确实现了 equals() 和 hashCode():比较的是值而非引用,且哈希值由值唯一确定。但要注意边界情况:
-
new String("abc").equals("abc")是true,但new String("abc") == "abc"是false -
Integer在 [-128, 127] 范围内会缓存,所以Integer.valueOf(100) == Integer.valueOf(100)成立;超出范围则不一定 - 永远别用
==比较两个Integer是否“值相等”,必须用.equals()
复杂点在于:一旦你组合这些类型(比如 Map),只要嵌套结构里的每一层都满足契约,整个集合的行为就是可预期的。最容易被忽略的是——你自己写的类,哪怕只作为某个多层嵌套对象中的一个字段,也必须守规矩。
# java
# 懒加载
# ai
# eclipse
# 为什么
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】
Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】
网站制作大概多少钱一个,做一个平台网站大概多少钱?
Laravel怎么在Controller之外的地方验证数据
Python企业级消息系统教程_KafkaRabbitMQ高并发应用
如何快速重置建站主机并恢复默认配置?
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
Laravel怎么上传文件_Laravel图片上传及存储配置
如何基于云服务器快速搭建网站及云盘系统?
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法
Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】
如何在阿里云服务器自主搭建网站?
高防服务器:AI智能防御DDoS攻击与数据安全保障
Laravel DB事务怎么使用_Laravel数据库事务回滚操作
奇安信“盘古石”团队突破 iOS 26.1 提权
Laravel如何配置和使用缓存?(Redis代码示例)
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
浅述节点的创建及常见功能的实现
合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?
java中使用zxing批量生成二维码立牌
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
googleplay官方入口在哪里_Google Play官方商店快速入口指南
Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能
如何确认建站备案号应放置的具体位置?
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
如何在香港免费服务器上快速搭建网站?
在线教育网站制作平台,山西立德教育官网?
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
在线制作视频的网站有哪些,电脑如何制作视频短片?
如何快速生成ASP一键建站模板并优化安全性?
Laravel如何实现一对一模型关联?(Eloquent示例)
如何用AI帮你把自己的生活经历写成一个有趣的故事?
EditPlus中的正则表达式 实战(1)
浅谈Javascript中的Label语句
Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】
如何在新浪SAE免费搭建个人博客?
Win11怎样安装网易有道词典_Win11安装词典教程【步骤】
在Oracle关闭情况下如何修改spfile的参数
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件
Laravel Vite是做什么的_Laravel前端资源打包工具Vite配置与使用
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
Python自动化办公教程_ExcelWordPDF批量处理案例
canvas 画布在主流浏览器中的尺寸限制详细介绍
详解CentOS6.5 安装 MySQL5.1.71的方法


