HashMap 1.7put方法源码分析

HashMap 默认初始容量 (16) 默认加载因子 (0.75)
扩容的两个前提条件:

  1. 存放新值的时候当前已有元素个数大于等于阈值
  2. 存放新值的时候当前存放数据发生hash冲突

这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中桶的数量,初始容量是创建哈希表时的容量,加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。对于使用链表法的散列表来说,查找一个元素的平均时间是O(1+a),因此如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费。系统默认负载因子为0.75,一般情况下我们是无需修改的。

JDK1.7以前的put方法

在这里插入图片描述inflateTable初始化数组容量 设置阈值(默认16)

该方法作用为获得一个2的次方数 且该数大于tosize
在这里插入图片描述
核心方法在这里插入图片描述在这里插入图片描述
该方法也是转成二进制进行位运算 非常巧妙
注意:所有2的次方数转成2进制后 只有一个1 如8转成二进制为 1000

对方法举例:假设某一数转成二进制 0001 xxxx (x为0 or 1)
先右移一位变为 0000 1xxx 在进行或运算变为 00011xxx
再右移两位 0000 011x 或运算 0001 111x
再右移四位 0000 0001 或运算 0001 1111

最后结果为 i = 0001 1111 将其与 i 右移一位的数相减
也就是 0001 1111 - 0000 1111 = 0001 0000 为二进制数 且该数一定小于等于 i 的初始值

jdk1.7以前由于HashMap的底层数据结构是“链表散列”,即数组和链表的组合,而数组是无法自动扩容的,所以只能是换一个更大的数组去装填以前的元素和将要添加的新元素

添加数据操作 是以key算出hashcode 然后将其对数组长度取模再添加(避免超过数组长度) 而实际底层操作没有取模 而是位运算
相应方法如下
在这里插入图片描述h为hashcode值 length为长度
计算效果:在这里插入图片描述
不管高位是什么数值 都没有影响 得到的数只与后四位有关 也就是0-15内

同时有弊端:某一条链表会特别长 影响get方法的效率
为了避免该弊端 提高散列性 所以在执行该方法前 执行了hash方法

在这里插入图片描述该方法则将hashcode的高位也加入了运算

至此得到了一个存放的下标 再进行for循环遍历链表
在这里插入图片描述如果新加入的值的key在链表中已经存在 hash值也相同 则将之前该值的value进行覆盖 并返回之前的value

如果新加入的值的key没有重复 则添加
在这里插入图片描述

先判断是否需要扩容
注意 该处size指的是整个hashmap的数据量 而不是指数组
在这里插入图片描述判断条件中size >= threshold对应如下
1.Capacity
HashMap的当前长度。HashMap的长度是2的幂。
2.LoadFactor
HashMap负载因子,默认值为0.75f。
threshold = Capacity * LoadFactor
HashMap.Size >= Capacity * LoadFactor
后面条件意思为 插入该数组的位置的链表有其他值 不为null

扩容 长度变为之前的两倍
注意: 是重新new一个新的数组
在这里插入图片描述在将之前的数据转移在这里插入图片描述先遍历之前table的元素(数组) 在遍历链表
接着进行头插法 将数据插入新表 此时新链表与原链表顺序是相反的 但是链表不分顺序 所以无所谓
在这里插入图片描述在这里插入图片描述

再添加进链表头部(头插法)
在这里插入图片描述表名头插法的代码
在这里插入图片描述
因为采用头插法 扩容后同一个链表上数据位置相反 如果多个线程同步操作 可能会导致死锁(扩容前 某链表是A—》B 扩容后是B—》A 两个线程同步操作 线程一进行扩容 线程二寻找该链表的某一值会A->B->A->B形成环形死锁)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值