HashMap底层源码学习,解析

HashMap是无序的,不可重复的。集合的默认初始化容量为16,默认的加载因子为0.75。这个加载因子就是说当HashMap集合底层数组的容量达到75%时,数组就开始扩容。初始化容量是2的倍数,为了达到散列均匀,提高集合的存取效率。
在这里插入图片描述
在这里插入图片描述
DEFAULT_INITIAL_CAPACITY:

初始容量,也就是默认会创建 16 个箱子,箱子的个数不能太多或太少。如果太少,很容易触发扩容,如果太多,遍历哈希表会比较慢。

在这里插入图片描述
MAXIMUM_CAPACITY:

哈希表最大容量,一般情况下只要内存够用,哈希表不会出现问题。

在这里插入图片描述
DEFAULT_LOAD_FACTOR:

默认的负载因子。因此初始情况下,当键值对的数量大于 16 * 0.75 = 12 时,就会触发扩容。

加载因子是表示Hash表中元素的填满的程度.加载因子越大,填满的元素越多,好处是,空间利用率高了;但是,冲突的机会加大了.反之,加载因子越小,填满的元素越少;好处是:冲突的机会减小了,但:空间浪费多了.冲突的机会越大,则查找的成本越高.反之,查找的成本越小.因而,查找时间就越小. 因此,必须在 "冲突的机会"与"空间利用率"之间寻找一种平衡与折衷. 这种平衡与折衷本质上是数据结构中有名的"时-空"矛盾的平衡与折衷.
加载因子是哈希表在其容量自动扩容之前可以达到多满的一种度量。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行扩容、rehash操作(即重建内部数据结构),扩容后的哈希表将具有两倍的原容量。
在这里插入图片描述
TREEIFY_THRESHOLD:

如果哈希函数不合理,即使扩容也无法减少箱子中链表的长度,因此 Java 的处理方案是当链表太长时,转换成红黑树。这个值表示当某个箱子中,链表长度大于 8 时,有可能会转化成树。

在这里插入图片描述
UNTREEIFY_THRESHOLD:

在哈希表扩容时,如果发现链表长度小于 6,则会由树重新退化为链表。

在这里插入图片描述
MIN_TREEIFY_CAPACITY:

在转变成树之前,还会有一次判断,只有键值对数量大于 64 才会发生转换。这是为了避免在哈希表建立初期,多个键值对恰好被放入了同一个链表中而导致不必要的转化。

在这里插入图片描述
modCount

用于记录HashMap的修改次数,在HashMap的put(),get(),remove(),Interator()等方法中,都使用了该属性。由于HashMap不是线程安全的,所以在迭代的时候,会将modCount赋值到迭代器的expectedModCount属性中,然后进行迭代,如果在迭代的过程中HashMap被其他线程修改了,modCount的数值就会发生变化,这个时候expectedModCount和ModCount不相等,迭代器就会抛出ConcurrentModificationException()异常

在这里插入图片描述
从上图我们可以发现数据结构由数组+链表组成,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key.hashCode())%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,(len表示map外层数组的大小,默认16)

**hash(key.hashCode())%len**
12%16=12,
28%16=12,
108%16=12,
140%16=12

所以12、28、108以及140都存储在数组下标为12的位置。

put()方法调用的过程解析:
在这里插入图片描述
第一步 将key,value封装到Node对象中;
第二步 则调用key的hashCode()方法取得hash值;
第三步 通过哈希算法/哈希表函数将hash值转换成数组的下标:
1,如果该下标位置上没有任何元素,就把该Node对象添加到这个位置上;
2,如果该下标位置已有链表存在,则将Node对象的key跟链表上的每个节点进行equals对比
3,如果对比结果为false则直接添加到该链表的末端,为true则替换该节点的value值。
4,当链表长度大于8时,链表会转换成红黑树,但如果当链表的长度小于6时,则红黑树结构又会转换成链表结构

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值