前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >重写equals方法必须重写hashcode

重写equals方法必须重写hashcode

作者头像
用户4415180
发布于 2022-06-23 06:26:53
发布于 2022-06-23 06:26:53
1.3K00
代码可运行
举报
文章被收录于专栏:高并发高并发
运行总次数:0
代码可运行

equals方法定义在java的根类Object类,定义如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public boolean equals(Object obj) {
        return (this == obj);
}

比较的是引用,也就是对象的地址是否相等,equals在非空对象上需要满足以下特性:

1.自反性:x.equals(x) == true,自己和自己比较相等

2.对称性:x.equals(y) == y.equals(x),两个对象调用equals的的结果应该一样

3.传递性:如果x.equals(y) == true y.equals(z) == true 则 x.equals(z) == true,x和y相等,y和z相等,则x和z相等

4.一致性 : 如果x对象和y对象有成员变量num1和num2,其中重写的equals方法只有num1参加了运算,则修改num2不影响x.equals(y)的值

x.equals(null)必须为false

知道了equals的特性,为啥重写equals必须要重写hashcode呢,其实这个不是语法定义,只是如果不重写hashcode在我们调用HashSet和HashMap的时候可能会造成歧义,也就是用equals方法判断的两个对象相等,但是hashcode不相等,会造成hashmap散列到不同数组下标,导致了哈希表中有两个相同的key,hashmap相同的key是可选的,但是默认是只能有唯一的key,hashset必须是唯一的key。hashmap插入代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
	    //先判断待插入结点和当前已插入结点hash值是否相等,如果相等说明同处于一个链表,然后判断两个结点key的引用是否相等
	    //如果引用相等,说明就是同一个值,equals必相等,如果引用不相等,则调用equals方法判断对象是否相等,如果相等说明
	    //当前key已经存在,插入的值会将旧key的vaule覆盖
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }

所以如果equals相等,但是hashCode不相等,会造成hashmap的hash函数不相等,然后hashmap就不会覆盖旧key,导致hashmap有两个相同的key,因为hashset就是用的hashmap,也会导致hashset逻辑出错,set集合有重复元素。

可以得出结论: 如果两个对象equals为true,则hashCode必须相等,如果equals不相等,hashCode可以相等可以不相等,这个要看hashCode的哈希函数设计,最好哈希函数就是冲突概率低。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
面试官:为什么重写 equals 同时要重写 hashCode? 我:…
重写equals是为了在业务逻辑上判断实例之间是否相等。重写hascode是为了让集合快速判重。
终码一生
2022/04/14
2850
引以为戒:避免在Set中使用未重写equals和hashCode的引用对象进行去重
在日常的Java开发中,我们经常会使用Set集合来实现去重操作,确保集合中不含有重复的元素。然而,如果使用未重写equals()和hashCode()方法的引用对象进行去重,可能会导致意外的行为,最近了在项目中就遇到了这个情况,让我们深入探讨这个问题,并引以为戒,确保正确实现去重操作。
修己xj
2023/08/25
4060
引以为戒:避免在Set中使用未重写equals和hashCode的引用对象进行去重
面试点:Java 中 hashCode() 和 equals() 的关系
Java 中 hashCode() 和 equals() 的关系是面试中的常考点,如果没有深入思考过两者设计的初衷,这个问题将很难回答。除了应付面试,理解二者的关系更有助于我们写出高质量且准确的代码。
TimeFriends
2022/09/05
5850
面试题系列第4篇:重写了equals方法,为什么还要重写hashCode方法?
这不仅仅是一道面试题,而且是关系到我们的代码是否健壮和正确的问题。在前面两篇文章涉及到了equals方法的底层讲解:《说说==和equals的区别?你的回答可能是错误的》和《Integer等号判断的内幕,你可能不知道?》。
程序新视界
2020/08/31
1.6K1
面试题系列第4篇:重写了equals方法,为什么还要重写hashCode方法?
HashSet的add()方法源码解析(jdk1.8)
因为通常声明map集合时不会指定大小,或者初始化的时候就创建一个容量很大的map对象,所以这个通过容量大小与key值进行hash的算法在开始的时候只会对低位进行计算,虽然容量的2进制高位一开始都是0,但是key的2进制高位通常是有值的,因此先在hash方法中将key的hashCode右移16位在与自身异或,使得高位也可以参与hash,更大程度上减少了碰撞率。
全栈程序员站长
2022/07/09
2450
JAVA中重写equals()方法为什么要重写hashcode()方法说明
重写hashCode()时最重要的原因就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。如果在将一个对象用put()方法添加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个 hashCode()值,那么就无法重新取得该对象了。所以,如果你的hashCode()方法依赖于对象中易变的数据,那用户就要小心了,因为此数据发生变化时,hashCode()就会产生一个不同的hash码,相当于产生了一个不同的“键”。        Object的hashCode()方法,返回的是当前对象的内存地址。下次如果我们需要取一个一样的“键”对应的键值对的时候,我们就无法得到一样的hashCode值了。因为我们后来创建的“键”对象已经不是存入HashMap中的那个内存地址的对象了。        我们看一个简单的例子,就能更加清楚的理解上面的意思。假定我们写了一个类:Person (人),我们判断一个对象“人”是否指向同一个人,只要知道这个人的身份证号一直就可以了。        先来个没有重写Code类的hashcode()的例子吧,看看是什么效果:
bear_fish
2018/09/20
1.1K0
JAVA中重写equals()方法为什么要重写hashcode()方法说明
HashMap源码分析
负载因子,当size大于threshold时进行扩容,threshold=capacity * loadFactor,capacity是当前数组长度,若当前桶大小为16,16*0.75=12,那么当哈希表中的存储的键值对数达到扩容阈值12时扩容,扩容为原来的2倍
Krains
2020/08/19
2830
HashMap源码分析
equals() ? ==? hashCode()? 今天就把你们都认识清楚
byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),基础数据类型比较的是他们的值。
Java宝典
2021/04/22
4520
这可能是最细的HashMap详解了!
# 手撕HashMap源码 > 文章已同步至GitHub开源项目: [Java超神之路](https://github.com/shaoxiongdu/java-notes) ### HashMap一直是面试的重点。今天我们来了解了解它的源码吧! > 首先看一下Map的继承结构图 ![image-20210906151448379](https://gitee.com/ShaoxiongDu/imageBed/raw/master/image-20210906151448379.png) > 源码
程序员阿杜
2021/09/11
2520
HashMap详解
**Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。**这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
程序员阿杜
2023/08/25
2710
程序猿的日常——HashMap的相关知识
背景知识 哈希冲突 哈希是指通过某种方法把数据转变成特定的数值,数值根据mod对应到不同的单元上。比如在Java中,字符串就是通过每个字符的编码来计算、数字是本身对应的值等等,不过就算是再好的哈希方法
用户1154259
2018/01/17
4300
程序猿的日常——HashMap的相关知识
HashSet 如何保证元素不重复——hash码
HashSet 不重复主要add 方法实现,使用 add 方法找到是否存在元素,存在就不添加,不存在就添加。HashSet 主要是基于HashMap 实现的,HashMap 的key就是 HashSet 的元素,HashSet 基于hash 函数实现元素不重复。首先看 add 方法:
用户10384376
2023/02/25
2250
HashSet 如何保证元素不重复——hash码
java为什么要重写hashCode和equals方法
      在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了。
业余草
2019/01/21
2.9K0
分析 JDK 源码丨Java HashMap
HashMap 是数组和链表组合组成的复杂结构,哈希值决定了键值在数组的位置,当哈希值相同时则以链表形式存储,当链表长度到达设定的阈值则会对其进行树化,这样做是为了保证数据安全和数据相关操作的效率
码脑
2019/10/29
3780
分析 JDK 源码丨Java HashMap
HashMap深度解析(一)
高爽
2017/12/28
7760
HashMap深度解析(一)
HashMap框架源码深入解读,面试不用愁
在Java Collections Framework的体系中中,主要有两个重要的接口,一个是List、Set和Queue所属的Collection,还有一个就是Map接口了。在上一篇文章中介绍了List接口,它适用于按数值索引访问元素的情形。本文中将介绍的Map则提供了一个更通用的元素存储方法。
李红
2019/09/05
3710
Java中Set集合是如何实现添加元素保证不重复的?
Java中Set集合是如何实现添加元素保证不重复的? Set集合是一个无序的不可以重复的集合。今天来看一下为什么不可以重复。 Set是一个接口,最常用的实现类就是HashSet,今天我们就拿HashSet为例。 先简单介绍一下HashSet类 HashSet类实现了Set接口, 其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。 先看下HashSet的几个构造方法。 // 默认构造函数 底层创建一个HashMap
武培轩
2018/04/17
1.5K0
【重点,要考的】数据结构及算法基础--哈希图(HashMap)
在了解HashMap前我们要先了解Object的两个方法:Equals和hashCode()
用户5640963
2019/07/26
3840
深入Java源码剖析之Set集合
HashSet实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。看下面的一个例子:
wangweijun
2020/02/14
5050
了解HashMap数据结构,超详细!
HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。
程序员的时光001
2020/11/02
5930
了解HashMap数据结构,超详细!
推荐阅读
相关推荐
面试官:为什么重写 equals 同时要重写 hashCode? 我:…
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文