jdk1.8中hashmap源码分析

jdk1.8中hashmap源码分析

本文以JDK 1.8.0_131源代码为例进行分析:

  • jdk1.6到1.8中hashmap的变化
  • hashmap的实现原理
  • 数组大小及相关参数规定
  • Hashmap的put方法实现
  • Hashmap的get方法实现

jdk1.6到1.8中hashmap的变化

  • JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。

    《jdk1.8中hashmap源码分析》

  • JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
    《jdk1.8中hashmap源码分析》

hashmap的实现原理

:采用的是“桶位”,即一个Node数组实现
《jdk1.8中hashmap源码分析》
Node节点的实现:主要包括了key、value以及key的哈希值和next指向一个节点。
《jdk1.8中hashmap源码分析》

数组大小及相关参数规定规定:

  • 所有的默认值:
    默认的数组初始容量:16
    《jdk1.8中hashmap源码分析》
    默认的最大容量:2的30次方
    《jdk1.8中hashmap源码分析》
    默认的负载因子:0.75
    《jdk1.8中hashmap源码分析》
    默认的链表转红黑树的节点数阈值:8
    《jdk1.8中hashmap源码分析》
    Hashmap扩容的节点数阈值threshold=capacity*load factor:
    《jdk1.8中hashmap源码分析》
  • 注意Hashmap中数组容量capacity的值总是2的n次方:
    当不是2的n次方时,会用下面的函数进行调整。
    《jdk1.8中hashmap源码分析》
    >>>表示无符号右移,无论是正数还是负数,高位通通补0。经过5次向右位移后,n一定会变成000..00111..11类型,即前部分均为0,后部分均为1.所以返回的调整后的容量为n+1,一定是2的n次方。

Hashmap的put方法实现:

《jdk1.8中hashmap源码分析》
《jdk1.8中hashmap源码分析》

说明:

  • 代码块1:如果Node数组为空,则通过resize()函数新建一个长度为capacity的数组,并赋值给table。

  • 代码块2:找到key的hash值在数组中的位置为i,即该hash表的寻址方法为i=(n-1)&hash。如果table[i]==null,则直接为该数组new一个Node,并存储key,value。
    (注意:此处的寻址方法很巧妙,实质上相当于是求hash%(n-1),但是位运算的效率更高。因为n总是 2 的倍数,假设
    hash=5,n=16, 那么hash&n-1将得到5;如果hash=6,n=16,那么hash&n-1将得到6……如果hash=15,n=16,那么hash&n-1将得到15;但是当hash=16,n=16时,那么hash&n -1将得到0了;当hash=17,n=16时,那么hash&n -1将得到1了……这样保证计算得到的索引值总是位于table数组的索引之内。)

  • 代码块3:如果table[i]!=null,并且table[i].key与要插入的key相等,则e=table[i],并通过代码块6直接更新table[i]的value。

  • 代码块4:如果table[i].next所连接的是红黑树,则将key,value插入后面的红黑树。

  • 代码块5:如果table[i].next所连接的不是红黑树,则说明table[i].next连接的是普通链表,则通过e=p.next,p=e,一直到p.next==null.再把要插入的key,value插入到p.next。相当于新节点插入到了链表的最后

  • 代码块7:通过size记录hashmap中元素的个数,如果size>threshold,则利用resize()对table数组进行扩容。
    《jdk1.8中hashmap源码分析》
    即,扩容过程为直接将table的capacity容量乘以2,并且阈值threshold也乘2

Hashmap的get方法实现:

《jdk1.8中hashmap源码分析》
《jdk1.8中hashmap源码分析》
说明:

  • 代码块1:如果table数组(也称为bucket桶)为null,或者数据的长度小于0,或者当对key的hash值进行寻址时,即i=(n-1)&hash,first=table[i],如果table[i]==null。则直接return
    null。
  • 代码块2:如果table[i]的key值与需要查询的目标key相等,则返回table[i]。注意:此处table[i].hash与key的hash值相同,所以必须通过key的equal方法来判断两个key是否相等,因此在当key应用于hashmap时必须同时实现hashcode和equal两个方法
  • 代码块3:如果table[i].next后面链接的是红黑树,则在红黑树中进行查找。
  • 代码块4:如果table[i].next后面链接的是普通链表,则在该链表中进行遍历,并通过key的equal方法查找key相同的节点,并返回。
    原文作者:自由不死
    原文地址: https://blog.csdn.net/yyc1023/article/details/80601687
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞