建议重写equals方法时也一并重写hashCode方法
Object类中有这样一段说明,意思是建议我们equals方法和hashCode方法,或者一起重写,或者一起不重写,以维护hashCode的常规协定。
什么叫hashCode的常规协定呢?
我的理解就是:两个对象通过equals方法进行比较相等,它们分别调用hashCode方法时一定返回相同的整数;两个对象通过equals方法比较不相等是,不要求它们调用hashCode方法时必须返回不同的值,但是程序员应该意识到,在这种情况下,让它们返回不同的可以提高哈希表的性能。
怎么又涉及到哈希表的性能呢?
其实,我们一般不会直接调用hashCode方法,但是在集合中它们会被频繁的使用。重写equals方法时建议重写hashCode方法,是针对像Map、Set这种集合操作而言的。
我们创建一个类,谁都不能保证它什么时候会被放到集合中,所以,为了避免不必要的麻烦,建议重写equals方法的同时也重写hashCode方法,重写hashCode方法的同时也一起重写equals方法。
其实,equals方法与hashCode方法不一致会带来两个比较明显的问题。
一、理解困难,容易混淆
二、查找效率低下,也就是所谓的哈希表的性能会降低
这又从何说起呢?
我们知道,HashMap底层维护的是一个Entry类型的数组,向HashMap中添加键值对时,首先通过Key值计算出一个位置,该位置可能就是此元素将要放置的位置。如果发现,这个位置上没有元素,也就是为null,那么就直接将这个待添加的元素放置在该位置上。如果这个位置上已经有元素存在,那么接着通过equals方法比较这个待添加的元素Key与已经存在的这个元素的Key是否相等,不相等则执行添加操作,相等则返回旧值不执行添加操作。注意,这种情况下执行添加操作是将待添加的元素放置这个位置上,然后让这个待添加的元素指向已经存在的这个旧元素,如此在这个位置上就形成了链表。同理,取出元素是和添加类似,是通过给定对象的hashCode()方法计算出一个位置,然后在该位置上进行查找,找到就返回该元素,否则返回null。
明白了这个过程就好办了。
如果equals方法与hashCode方法一致,那么在HashMap所维护的那个Entry类型的数组中的每个位置上就只有一个元素,而不会形成链表,这样一来查找的性能就非常好,同时理解上也十分清晰明了。反之,如果二者不一致,就有可能造成难以理解或者查找的性能比较低。
下面以String类举例说明:
假设String类只重写了equals()方法,而没有重写hashCode()方法。也就是说其hashCode()方法仍然继承Object类的hashCode()方法。
看下面的代码段
HashSet set = new HashSet();
String s1 = new String("hello");
String s2 = new String("hello");
set.add(s1);
set.add(s2);
System.out.println(set.size()); //输出为2
此时,set中有两个元素,这两个元素的内容都为"hello",它们存储在数组中的不同位置上,因为
两个对象的hashCode()返回值不同。
如果我们将set中的元素迭代出来,就会看到两个"hello"。这就造成了理解上困难了,因为在我
们的记忆中set中的元素是不能重复的,但现在这个HashSet对象中却有两个"hello",这怎么解释
呢?虽然,它们实际上是两个不同的对象,但从表象上看它们确实是“一样的”,也只有构造这 个HashSet对象的我们知道,但是其它调用者却很难理解,这就是所谓的理解上的混乱。
假如String类只重写了hashCode()方法,而没有重写hashCode()方法。
同样,我们看上面那段代码
set中仍然有两个元素,但是相对于HashMap底层的那个Entry数组来说,这两个元素在相同的位置上,并且形成了链表,s2指向s1,因为s1和s2的hashCode()返回值相同,但通过equals()方法进行比较却返回false。
这样一来,查找起来就比较费劲了,因为要遍历链表。
我们知道,链表遍历只能是通过前一个元素找下一个元素。
我们这里是两个对象,找起来可能不那么费力,但是对象多了呢?链表长了呢?
这就是所谓的效率低。
这两点就造成了我们前面提到的哈希表的性能的下降。
综上所诉,虽然不强制要求重新equals方法时必须重写hashCode方法或者是重写hashCode方法必须重写equals方法,但是为了避免不必要的麻烦,建议二者要么一起重写,要么都不重写,以保持它们的一致性。
以上是作者的一点点理解,如有纰漏之处,还请多多指教。
本文转自 手不要乱摸 51CTO博客,原文链接:http://blog.51cto.com/5880861/1335139
建议重写equals方法时也一并重写hashCode方法相关推荐
- 为什么重写equals()就一定要重写hashCode()方法
Object类,所有类的父类 一.为什么重写equals()方法一定要重写hashCode()方法 1.首先解释equals方法和hashcode方法分别是用来干什么的? equals()方法: 在O ...
- java -为什么重写equals(),还需要重写hashCode()?
1.先post这两个方法的基本定义: equals()的定义: 浅谈Java中的equals和==(转) hashCode()的定义: java中hashCode()方法的作用 Java中hashCo ...
- [改善Java代码]覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
- why在重写equals时还必须重写hashcode方法
首先我们先来看下String类的源码:可以发现String是重写了Object类的equals方法的,并且也重写了hashcode方法 public boolean equals(Object anO ...
- java 重写equals的要点_重写equals 方法的注意事项
java.lang.Object 中的equals方法如下 public boolean equals(Object obj) { return (this == obj); } 什么时候需要重写eq ...
- java重写面试题_Java面试题:重写了equals方法,为什么还要重写hashCode方法?
核心问题:重写了equals方法,为什么还要重写hashCode方法? 这不仅仅是一道面试题,而且是关系到我们的代码是否健壮和正确的问题.在前面两篇文章涉及到了equals方法的底层讲解:<说说 ...
- 为什么重写equals方法必须要重写hashCode方法
为什么重写equals方法必须要重写hashCode方法 了解这个问题之前我们得需要知道hashCode的作用.equals方法和hashCode方法都是Object类中的基础方法,用来判断两个对 ...
- JAVA中重写equals()方法的同时要重写hashcode()方法
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...
- JAVA中list.contains()方法,要重写equals(),hashcode()方法
今天动力节点java培训机构小编为大家介绍"JAVA中list.contains()方法,要重写equals(),hashcode()方法",希望能够帮助正在学习java的零基础学 ...
最新文章
- 基于STM32F103RE ADDA板制作
- 区跨链应用 | 区块链创业者不要再骗自己了
- python的_thread模块来实现多线程(python核心编程例子)
- 人脸识别之insightface开源代码使用:训练、验证、测试(4)
- 取消挂载点可以节省磁盘么_磁盘克隆、磁盘镜像还有复制粘贴有什么不一样?...
- Unity HDRP中的光照烘焙测试(Mixed Lighing )和间接光
- zero ecilpse下载_推荐10个免费图片下载网站,助你摆脱找图烦恼!建议收藏
- 软件测试--cookie学习
- 数学竖式排版中不为人知的技巧
- OpenCV 线性滤波
- 哈工大中文分词系统ltp4j使用总结
- 如何修改报表平台中数据决策系统登陆地址
- STM32 HAL库BH1750光强检测器驱动代码
- php 递归 递归方式与算法
- mysql导入指定数据库_mysql命令行导入sql文件到指定数据库的方法
- tableau自定义地图
- SFI立昌SHN方案与应用
- 《机电传动控制》第六周作业
- PX4代码学习系列博客(5)——在px4中添加自己的模块
- 好用的数据库客户端工具