HashMap源码分析

HashMap内部的结构在这里插入图片描述
它可以看做是数组和链表结合组成的符合结构,数组被分为一个个桶,通过哈希值决定了键值对在这个数组的寻址;哈希值相同的键值对,则以链表形式存储。如果链表大小超过阈值,图中的链表就会被改造成树形结构。

从非拷贝构造函数的实现来看,这个表格(数组)似乎并没有在最初就初始化好,仅仅设置了一些初始值而已。所以,也许HashMap是按照lazy-load的原则来进行初始化。在这里插入图片描述
put方法:在这里插入图片描述
在这里插入图片描述

如果表格是null,resize方法会负责初始化它,这从tab = resize()可以看出。
resize方法兼顾两个职责,创建初始存储表格,或者在容量不满足需求的时候,进行扩容(resize)。
在放置新的键值对的过程中,如果发生下面条件,就会发生扩容。
在这里插入图片描述

在这里插入图片描述

仔细观察哈希值的源头,我们会发现,它并不是key本身的hashCode,而是来自于HashMap内部的另外一个hash方法。
在这里插入图片描述
注意,为什么这里需要将高位数据移位到低位进行异或运算呢?这是因为有些数据计算出的哈希值差异主要在高位,而HashMap里的哈希寻址是忽略容量以上的高位的,那么这种处理就可以有效避免类似情况下的哈希碰撞。

resize方法

fnal Node<K,V>[] resize() {
 // ...
 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACIY &&
 oldCap >= DEFAULT_INITIAL_CAPAITY)
 newThr = oldThr << 1; // double there
 // ... 
 else if (oldThr > 0) // initial capacity was placed in threshold
 newCap = oldThr;
 else { 
 // zero initial threshold signifes using defaultsfults
 newCap = DEFAULT_INITIAL_CAPAITY;
 newThr = (int)(DEFAULT_LOAD_ATOR* DEFAULT_INITIAL_CAPACITY;
 }
 if (newThr ==0) {
 foat ft = (foat)newCap * loadFator;
 newThr = (newCap < MAXIMUM_CAPACITY && ft < (foat)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);
 }
 threshold = neThr;
 Node<K,V>[] newTab = (Node<K,V>[])new Node[newap];
 table = n;
 // 移动到新的数组结构e数组结构
 }

依据resize源码,不考虑极端情况(容量理论最大极限MAXIMUM_CAPACITY指定,数值为 1<<30,也就是2的30次方),我们可以归纳为:
门限值等于(负载因子)x(容量),如果构建HashMap的时候没有指定它们,那么就是依据相应的默认常量值。
门限通常是以倍数进行调整 (newThr = oldThr << 1),我前面提到,根据putVal中的逻辑,当元素个数超过门限大小时,则调整Map大小。
扩容后,需要将老的数组中的元素重新放置到新的数组,这是扩容的一个主要开销来源。

.容量、负载因子和树化
为什么我们需要在乎容量和负载因子呢?
这是因为容量和负载系数决定了可用的桶的数量,空桶太多会浪费空间,如果使用的太满则会严重影响操作的性能。极端情况下,假设只有一个桶,那么它就退化成了链表,完全不能提供所谓常数时间存的性能。

负载因子 * 容量 > 元素数量
如果没有特别需求,不要轻易进行更改,因为JDK自身的默认负载因子是非常符合通用场景的需求的。
如果确实需要调整,建议不要设置超过0.75的数值,因为会显著增加冲突,降低HashMap的性能。
如果使用太小的负载因子,按照上面的公式,预设容量值也进行调整,否则可能会导致更加频繁的扩容,增加无谓的开销,本身访问性能也会受影响。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值