HashSet去重复原理解析

HashSet去重分为2种情况:

第一种HashSet的泛型是基本数据类型

1、int类型

(1)分析
我们将int类型本身的数据作为HashCode就可以,符合HashCode的条件。
为了更具有说服力,我们来看一下java(JDK1.8)官方的处理方式。
(2)源码

在这里插入图片描述

2、float类型

(1)分析
我们知道float是由32位二进制组成,int也是由32位二进制组成,所以我们只需要将float的二进制数转成int类型就OK了。下面我们来看一下源码

(2)源码
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

第三张图就是将float的二进制转化成int的原理。
比如:10.5对应的HashCode是1093140480

3、long类型

(1)分析
对于long而言,其是由64位二进制数组成,求long类型HashCode的解决方案是将long类型的“高32位”与“低32位”进行“亦或(^)”运算,然后取运算结果的“低32位”。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后将其转化成整型就OK了。

线面我们来看看源码:

(2)源码
在这里插入图片描述
这样就符合我们的分析结果了。

4、double类型

(1)分析
对于double而言,会将其二进制先转成long类型的二进制,然后再将long类型转成int(方法同上)。
我们直接看源码吧

(2)源码

自

5、boolean类型

(1)分析
对于Boolean类型其实是最简单的,因为Boolean类型就只有true和false两种,那么我们只需要认为规定两个数字作为其HashCode就可以。

(2)源码
我们来看一下java官方给Boolean类型规定的两个数字是什么

官方给的是固定值进行区分
在这里插入图片描述

6、String类的HashCode的实现原理以及计算

(1)分析
对于String类型而言,其实是可以类比进制计算的方式来规定,我们举一个例子:
对于12345这么一个整数,其实就是(1*10^4) + (2 * 10^3) +(3 *10^2) + (2 * 10^1) +(1 * 10^0)

那么对于“abcd”而言,我们是到‘a’本身即是可以用ascall码,那么我们是不是可以类比上面的计算:
“abcd” = (a * n^3) +(b *n^2) + (c * n^1) +(d * n^0)

怎么解决啥你那的问题呢?看下图

解决了重复计算的问题,先一步是确定n为多少合适。我们应该选用31作为n,因为31是一个奇素数,JVM会将“31 * i”优化成“(i<<5)- i”。很明显位运算要比乘运算高效的多。

(2)手动实现
在这里插入图片描述

在这里插入图片描述
我们发现官方提供的计算和我们自己写的得出结果是一样的。

(3)源码分析
在这里插入图片描述
字符串计算哈希值是把字符串拆分为字符数组,然后分别去计算每个字符的值进行累加,最后返回,当然这里的字符是要转化为ascall码的。

第二种是自定义对象

在这里插入图片描述

现在考虑有这样一个问题,当向一个HashSet集合中添加2个Student对象,但是这2个对象的属性:学生的姓名、年龄以及学号都是相同的,那么我们需要HashSet集合认为这2个是一个对象,那么我们就需要改对象的哈希值计算的一样。,因为我们在向集合中存储数据,首先是要判断哈希值的
那么这个时候我们来看下面的2种情况。

1、第一种:不重写hashCode方法和Equal方法

如果不重写hashCode方法和Equal方法,那么这两个对象是都可以添加成功的。
HashSet list=new HashSet();

hash值不相同,那么肯定可以添加成功
在这里插入图片描述

2、第二种:重写了系统的hashCode方法和equals方法

如果重写了系统的hashCode方法和equals方法,那么就只允许添加第一个对象,第二个对象是不会添加的

这是因为 通过 对象属性计算的hash值 ,因为对象里面的属性都一直,那么 hash值是一致的,euqals判断也一致,所以就不会进行添加。
在这里插入图片描述
在这里插入图片描述

3、第三种个性化定制,自己重写hashCode方法和equals方法

现在企业招2个人,只要是28岁的我都招,但是我只招一个,所以下面只有一个添加成功
在这里插入图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值