网站首页 > 技术文章 正文
1. equals 和 hashCode 方法之间的关系
这两个方法都是 Object 的方法,意味着 若一个对象在没有重写 这两个方法时,都会默认采用 Object 类中的方法实现,它们的关系为:
- 如果两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同。
- 如果两个对象hashCode相同,不能证明两个对象是同一个对象(不一定相等),只能证明两个对象在散列结构中存储在同一个地址(不同对象hashCode相同的情况称为hash冲突)。
2.为什么重写equals 后需要重写 hashCode
Effective Java 第三版 中 描述为什么重写equals 方法后必须重写hashCode 方法:
每个覆盖了equals方法的类中,必须覆盖hashCode。如果不这么做,就违背了hashCode的通用约定,也就是上面注释中所说的。
进而导致该类无法结合所以与散列的集合一起正常运作,这里指的是HashMap、HashSet、HashTable、ConcurrentHashMap。
上面注释 为 Object 类中 hashCode 方法注释:
If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
结论:如果重写equals不重写hashCode它与散列集合无法正常工作。
3. 以 HashMap 为例进行论证分析
查看 hashMap 的 put 方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
查看hash 方法的实现:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
查看 get 方法的实现:
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
java中HashMap的数据结构是数组+链表+红黑树;这种数据结构,每个键值对都会被存在相应的地址中,从代码中可以看出HashMap是通过key的hashCode以及自身的容量来决定当前键值的存储索引(桶)的,确定桶的位置后,再进入桶中同时判断hashCode和equals两个方法。那也就是说,如果hashCode不同,那么HashMap就一定会创建一个新的Node键值对象。
HashMap在put一个键值对时,会先根据键的hashCode和equals方法来同时判断该键在容器中是否已经存在,如果存在则覆盖,反之新建。所以如果我们在重写equals方法时,没有重写hashCode方法,那么hashCode方法还是会默认使用Object提供的原始方法,而Object提供的hashCode方法返回值是不会重复的(也就是说每个对象返回的值都不一样)。所以就会导致每个对象在HashMap中都会是一个新的键。
反向论证:若一个类中重写了 equals 方法,没有重写hashCode方法;且该类的两个对象具有不同属性但 hashCode 相等,在hashMap 以该对象为键进行存储时,会出现hash冲突现象,但发现该类重写了equals 方法,且通过该类的equals 比较之后也是相等,就会出现 hashMap 中只保存了一个对象,采用get 方法获取时,就会获取到别的对象,从而导致获取对象错乱。
因此 重写equals 方法必须重写 hashCode 方法,用来保证两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同 这一原则;
文章来自https://www.cnblogs.com/zjdxr-up/p/16177068.html
- 上一篇: 写代码的这群人不写文档,为什么 (上篇)
- 下一篇: Java 性能优化:教你提高代码运行的效率
猜你喜欢
- 2024-10-07 Android 设备上可以实现 3D Touch 吗?| 原力计划
- 2024-10-07 从 Kotlin 开发者的角度来看,Java 缺少了什么?
- 2024-10-07 Java 性能优化:教你提高代码运行的效率
- 2024-10-07 写代码的这群人不写文档,为什么 (上篇)
- 2024-10-07 你真的了解java反射机制吗?看看阿里大牛是怎么看反射的,细致
- 1515℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 579℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 515℃MySQL service启动脚本浅析(r12笔记第59天)
- 487℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 486℃启用MySQL查询缓存(mysql8.0查询缓存)
- 471℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 451℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 449℃MySQL server PID file could not be found!失败
- 最近发表
-
- 宝塔面板Nginx如何提高网站访问速度?
- 接口调试工具ApiPost中form-data/x-www-form-urlencoded/raw区别
- 高并发场景下,Nginx性能如何提升10倍?
- 高并发场景下,Nginx如何抗住千万级流量?
- 浏览器中在线预览pdf文件,pdf.mjs插件实现web预览pdf
- 为什么你的网站加载慢?90%的人忽略了这2个设置。
- 别再无脑复制Nginx配置了!掌握这10个"性能核弹"级参数
- 你的Nginx配置,可能就是你网站最慢的一环,注意这几个优化参数
- 深入浅出HTTP压缩技术(http2压缩)
- C程序设计之:1-1/2+1/3-... + 1/n 的和
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (83)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)