1.8 HashMap源码浅析

  Jdk 1.8

  
      <李>   

    数据结构

      
      

    1.8的版本的HashMap采用数组+链表+红黑树的数据结构来存储数据,还是通过散列,(选项卡。长度- 1)来确定在数组的位置,不过在数据的存储方面加了一个红黑树,当链表的大于等于8时,并且表的长度大于等于64时,就把这个链树化,不然还是扩容。增加红黑树,是为了提高查找节点的时间。结构如下图所示。

         

     HashMap源码浅析1.8

      李   <李>   

    基本成员变量
    <强> 强能力容量

      
     <代码>/* *
      *初始容量
      */静态最终int DEFAULT_INITIAL_CAPACITY=1 & lt; & lt;4;//即16  
      

    <强> max_capacity 最大容量

      
     <代码>/* *
      *最大容量
      */静态最终int MAXIMUM_CAPACITY=1 & lt; & lt;30; 
      负载系数

    <强> 强负载因子

      
     <代码>/* *
      *负载因子
      */静态最终浮DEFAULT_LOAD_FACTOR f=0.75;  
      

    <强> treeify_threshold 树化(转换为红黑树)的阈值

      
     <代码>//链表转为红黑树的阈值,第9个节点
      静态最终int TREEIFY_THRESHOLD=8; 
      

    <强> untreeify_threshold 强转换为链表的阈值

      
     <代码>//红黑树转为链表的阈值,6个节点转移
      静态最终int UNTREEIFY_THRESHOLD=6;  
      

    <强> min_treeify_capacity 树化的最小容量

      
     <代码>//转红黑树时,表的最小长度
      静态最终int MIN_TREEIFY_CAPACITY=64;  
      

    <强>节点链表

      
     <代码>静态类Node实现Map.Entry{//当前节点的哈希
      最后int散列;
      最后K键;
      V值;//指向下个节点
      Node下一个;
      
      节点(int散列,K键,V值,Node下一个){
      这一点。散列=散列;
      这一点。键=键;
      这一点。值=https://www.yisu.com/zixun/value;
      这一点。下一个=下一个;
      } 
      

    <强> TreeNode 红黑树

      
     <代码>静态最终类TreeNode扩展LinkedHashMap.Entry{
      TreeNode父母;//父节点
      TreeNode离开;//左儿子节点
      TreeNode对的;//右儿子基点
      TreeNodeprev;//上一个节点
      布尔红;//是否为红色
      TreeNode (int散列,K键,V val, Node下一个){
      超级(散列键,val,下一个);
      } 
      李   <李>构造方法
    <强>有参构造(和1.7一样)   
     <代码>公共HashMap (int initialCapacity浮动负载系数){
      如果(initialCapacity & lt;0)
      把新的IllegalArgumentException(“非法初始容量:“+
      initialCapacity);
      如果(initialCapacity比;MAXIMUM_CAPACITY)
      initialCapacity=MAXIMUM_CAPACITY;
      如果(负载系数& lt;=0 | | Float.isNaN负载系数())
      把新的IllegalArgumentException(“非法装载因子:“+
      负载系数);
      这一点。负载系数=负载系数;
      这一点。阈值=tableSizeFor (initialCapacity);
      } 
      

    <强>无参构造(和1.7一样)

      
     <代码>公共HashMap () {
      这一点。负载系数=DEFAULT_LOAD_FACTOR;//所有其他字段违约
      } 
      <李>   

    基本方法
    <强>把()方法
    执行流程:
    (1)判断当桌子前有没有初始化,没有就调用调整()方法初始化。(调整方法既是扩容也是初始化)
    (2)判断算出的位置我处有没有值,没有值,创建一个新的节点,插入我位置。
    (3)当我前位置有值,判断头结点的散列和关键是否和传入的关键和散列相等,相等则记录这个e。
    (4)与头节点的关键和散列不同,判断节点是否是树节点,如果是,调用树节点的插入方法putTreeVal()方法。(占时不了解红黑树的底层方法实现逻辑,待续)。
    (5)不是树结构,那证明是链表结构,遍历链表结构,并记录链表长度binCount。主要做了两步,(1)在链表里找到和传入的关键和散列相等的基点,并记录,(2)没有找的到,创建一个节点,插入链表的尾部,并判断链表长度有没有大于等于8,如果是就调treeifyBin方法决定是否需要树化。
    (6)判断前面记录的e节点是否为空,不为空证明找到了相同的基点,那就替换价值,返回oldValue。
    (7)整个插入流程已经结束,接下来要判断是否需要扩容,如果(+ +大小比;阈值)满足,那么就调用扩容方法调整();

      
     <代码>公共V把(K键,V值){
      返回putVal(散列(关键)、关键值,假的,真的);
      }/* *
      *把
      */最后V putVal (int散列,K键,V值,布尔alt=" HashMap源码浅析1.8”> 

    1.8 HashMap源码浅析