ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java中equals和hashCode方法为什么总是需要重写?

2021-11-04 08:33:48  阅读:163  来源: 互联网

标签:java HashMap Object equals hashCode 链表 hash 重写


equals和hashCode都是Object类的方法。意味着我们的任何对象都具有这两个方法,并可以重写它们。

首先,我们需要知道这两个方法是做什么的?

equals方法用来判断两个对象是否 “ 相等 ” 。
Object类上是将两个对象的地址进行比对,但是这样的规则,并不符合实际生活上的我们是怎么判断两者是否相等的。因此你需要进行重写,写自己的判断规则。
如:我们需要比较两个学生的年龄是否相等,Object类的equals则是比较这两个学生是否是同一个人。我们就只对其年龄进行比较。

hashCode方法返回此对象的散列值,而散列值的生成方式也可以自己进行重写。Object类的hashCode是返回对象的内存地址。

以上两个方法之间的联系是:若两个对象 “ 相等 ” ,那么它们返回的散列值也必须相同。(这是需要重写hashCode的第一个原因)
反之,则不然,若散列值相同,也不能直接判断两个对象 “ 相等 ”,还需经过equals方法的验证。

那么我们为什么需要重写hashcode方法呢?

与hashCode有关的一定有散列操作,我们随便举一个栗子:HashMap。

HashMap的存储结构是:数组+链表、红黑树,而其中存放的数据的结构是:<键,值>,

图示存储结构(取自网络)

 

 


在调用HashMap的put方法添加数据Entry时,会调用键对象的hashCode方法获取散列值,接着我们根据该值调用hash(Object key)方法获取新值。

    //扰动函数,为了使散列效果好,减少碰撞冲突
    static final int hash(Object key) {
        int h;
        return key == null ? 0 : (h = key.hashCode()) ^ h >>> 16;
    }

通过hash(Object key)的返回值,再依据HashMap的当前容量长度(即数组长度)做位运算与的操作(tab[i = (n - 1) & hash])),获取Entry在数组中的存放位置。

补充:
若该位置上没有数据,即直接存放即可。
若该位置上存在值(即hash冲突),则利用头插法 or 尾插法插入其中,形成链表。
若该位置上的链表长度大于等于8,链表即可转换为红黑树,提高查找效率。另外,当处于红黑树结构的链表长度小于6又会重新转换成链表。(为什么不直接小于8就将红黑树转换为链表,答:转换结构也是比较耗资源的)

总结

就是,当你需要使用散列操作(一般来说是为了更高的效率),你需要重写hashCode,因为默认的hashCode的返回值是对象在内存中的地址。这样的结果就是每一个对象的散列值都是独一无二的(即使其内容一致),那么在HashMap这种集合中,你就无法通过构造内容一致的键去获取map中的值。

以下图示HashSet添加数据的流程(取自网络)

 

标签:java,HashMap,Object,equals,hashCode,链表,hash,重写
来源: https://www.cnblogs.com/ruiyao18369/p/15506592.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有