面试官问:==和equals()有什么区别?为什么重写equals必须重写hashCode?(附图解+避坑指南)

发布时间:2026/6/16 8:33:27

面试官问:==和equals()有什么区别?为什么重写equals必须重写hashCode?(附图解+避坑指南) 面试官问和equals()有什么区别为什么重写equals必须重写hashCode附图解避坑指南摘要认地址equals认内容hashCode定位置。地址可不同内容同则位置必同。本文用一图看懂 房产证比喻 HashMap 底层原理 现代 Java 最优解record带你彻底拿下这道面试必考题。 系列导航上一篇面试官问基本类型和引用类型到底有什么不同下一篇预告面试官问String、StringBuilder、StringBuffer有什么区别待发布全部85题目录点击查看 面试还原面试官和equals()有什么区别为什么重写equals()时必须重写hashCode()这道题从初级到高级都会问但能答透“为什么必须重写 hashCode”的人不到30%。今天用一张图 房产证比喻 HashMap 底层原理让你彻底拿下。 一图看懂HashMap 存取原理金句记忆认地址equals认内容hashCode定位置。地址可不同内容同则位置必同。 生活比喻房产证 vs 身份证号 比房产证上的地址是否完全一样是不是同一套房。equals()重写后 比两套房子的朝向、面积、装修是否相同内容相等。hashCode() 这套房子所在的小区编号 楼栋编号。同一个小区/楼栋的房产哈希值大致相同。如果两个房子内容相同equals为 true它们必须在同一个小区/楼栋hashCode相等否则在“房产管理系统”中会放到不同分区永远找不到对方。 关键对比表vsequals()维度运算符equals()方法基本类型比较数值是否相等不能用于基本类型编译报错引用类型比较内存地址是否同一对象默认比较地址String、Integer等重写后比较内容能否重写不能运算符语法固定能Object 的方法可重写调用方式直接a ba.equals(b)需判空否则 NPE典型场景判断是否同一个对象基本类型数值比较判断业务内容是否相等如两个用户 ID 相同 三大常见坑点坑1equals()调用时未判空Stringsnull;System.out.println(s.equals(hello));// NullPointerException!正确hello.equals(s)或Objects.equals(s, hello)。坑2Integer的与equals()混用Integera100,b100;Integerc200,d200;System.out.println(ab);// true缓存System.out.println(cd);// false超出缓存System.out.println(c.equals(d));// true正确包装类比较数值一律用equals()。坑3只重写equals()不重写hashCode()→ HashMap 灾难classUser{Stringname;User(Stringname){this.namename;}Overridepublicbooleanequals(Objectobj){if(thisobj)returntrue;if(!(objinstanceofUser))returnfalse;returnname.equals(((User)obj).name);}// ❌ 没有重写 hashCode}// 使用MapUser,StringmapnewHashMap();Useru1newUser(张三);Useru2newUser(张三);map.put(u1,数据);System.out.println(map.get(u2));// null原因HashMap.get()先算hashCode定位桶u1和u2哈希不同分到不同桶equals()根本用不上。 面试官追问重点追问1equals()和在 String 中具体怎么工作答String重写了equals()比较字符序列。字面量String s1 a; String s2 a;会先去字符串常量池检查有就复用所以s1 s2为 true。new StringString s3 new String(a);强制在堆中创建新对象s1 s3为 false。追问2重写hashCode()时应该遵循什么规则现代 Java 推荐写法答三条规则 现代写法规则同一对象多次调用hashCode()返回相同整数前提是equals比较的信息没变。如果两个对象equals()返回 true则hashCode()必须相等。如果两个对象equals()返回 falsehashCode()可以相等哈希碰撞但为了性能尽量不等。现代写法推荐OverridepublicinthashCode(){returnObjects.hash(name,age);// 简洁、不易错}传统手动计算31 * result ...的方法已被Objects.hash取代。追问3HashMap 中先比 hashCode 再比 equals 有什么好处答直接equals遍历所有元素时间复杂度 O(n)。先hashCode分桶平均 O(1) 定位到小范围再equals确认。哈希码相等不保证对象相等所以还要equals最终判定。追问4有没有办法从根本上避免手动重写equals和hashCode答现代 Java 最优解使用recordJava 14 正式特性Java 17 LTS 普及。recordUser(Stringname,intage){}record自动生成了equals、hashCode、toString和构造器完全基于组件值。强烈推荐只要是数据载体类优先使用record从根本上杜绝“忘记重写 hashCode”的 Bug。 可运行验证代码importjava.util.HashMap;importjava.util.Map;importjava.util.Objects;publicclassEqualsHashCodeDemo{// 正确示例使用 record最简洁recordUser(Stringname,intage){}// 错误示例手写但忘记 hashCodestaticclassBadUser{Stringname;BadUser(Stringname){this.namename;}Overridepublicbooleanequals(Objectobj){if(!(objinstanceofBadUser))returnfalse;returnname.equals(((BadUser)obj).name);}// 没有重写 hashCode}publicstaticvoidmain(String[]args){// 使用 recordUseru1newUser(张三,25);Useru2newUser(张三,25);System.out.println(record equals: u1.equals(u2));// trueSystem.out.println(record hashCode: (u1.hashCode()u2.hashCode()));// trueMapUser,StringmapnewHashMap();map.put(u1,数据);System.out.println(map.get(u2) map.get(u2));// 数据// 错误示例BadUserbu1newBadUser(李四);BadUserbu2newBadUser(李四);MapBadUser,StringbadMapnewHashMap();badMap.put(bu1,数据);System.out.println(只重写equals不重写hashCode: badMap.get(bu2));// null}}❓ 评论区挑战问题下面代码的输出是什么为什么Strings1newString(java);Strings2newString(java);System.out.println(s1s2);System.out.println(s1.equals(s2));A. true / falseB. false / trueC. false / falseD. true / true投票区已开启欢迎留下你的答案和理由。《面试官Java 中的基本类型和引用类型有什么区别 比较它们时行为一样吗》 评论区挑战问题Integerxnull;inty10;System.out.println(xy);A. falseB. trueC. 编译报错D. 运行时抛出异常✅ 答案公布正确答案D. 运行时抛出异常解析x y触发自动拆箱即x.intValue() 10。由于x为null调用null.intValue()抛出NullPointerException。因此程序不会输出 false 或 true而是直接抛出异常。你答对了么如果答案错误请温习《面试官Java 中的基本类型和引用类型有什么区别 比较它们时行为一样吗》 文章中相关内容。 系列导航上一篇面试官问基本类型和引用类型到底有什么不同下一篇预告面试官问String、StringBuilder、StringBuffer有什么区别待发布全部85题目录点击查看你在实际开发中遇到过因为没重写hashCode()导致的诡异 Bug 吗或者已经用上了record彻底告别这个坑欢迎评论区分享你的故事。

相关新闻