java基础类型源码解析之多角度讲HashMap

  

  

终于来到比较复杂的HashMap,由于内部的变量、内部类,方法都比较多,没法像ArrayList那样直接平铺开来说,因此准备从几个具体的角度来切入。

  


  

  

HashMap的每个存储位置,又叫做一个桶,当一个Key&价值进入地图的时候,依据它的散列值分配一个桶来存储。

  

看一下桶的定义:表就是所谓的桶结构,说白了就是一个节点数组。

        瞬态Node[]表;   瞬态int大小;      

<强>节点
  

  

HashMap是一个地图结构,它不同于收集结构,不是存储单个对象,而是存储键值对。
  

  

因此内部最基本的存储单元是节点:节点。

  

节点的定义如下:

        类Node实现Map.Entry{   最后int散列;   最后K键;   V值;   Node下一个;   }      

可见节点除了存储关键,影响无锡市,散列三个值之外,还有一个下一个指针,这样一样,多个节点可以形成一个单向列表。这是解决哈希冲突的一种方式,如果多个节点被分配到同一个桶,可以组成一个链表。

  

HashMap内部还有另一种节点类型,叫做TreeNode:

        类TreeNode扩展LinkedHashMap.Entry{   TreeNode父母;//红黑树链接   TreeNode离开;   TreeNode对的;   TreeNodeprev;//需要拆开下删除   布尔红;   }      

TreeNode是从节点继承的,它可以组成一棵红黑树。为什么还有这个东东呢?上面说过,如果节点的被哈希到同一个桶,那么可能导致链表特别长,这样一来访问效率就会急剧下降。此时如果关键是可比较的(实现了可比接口),HashMap就将这个链表转成一棵平衡二叉树,来挽回一些效率。在实际使用中,我们期望这种现象永远不要发生。

  

有了这个知识,就可以看看HashMap几个相关常量定义了:

        静态最终int TREEIFY_THRESHOLD=8;   静态最终int UNTREEIFY_THRESHOLD=6;   静态最终int MIN_TREEIFY_CAPACITY=64;      
      <李> TREEIFY_THRESHOLD,当某个桶里面的节点数达到这个数量,链表可转换成树;李   <李> UNTREEIFY_THRESHOLD,当某个桶里面数低于这数量,树转换回链表;李   <李> MIN_TREEIFY_CAPACITY,如果桶数量低于这个数,那么优先扩充桶的数量,而不是将链表转换成树;李   
  

<强>把方法:Key&价值
  

  

插入接口:

        公共V把(K键,V值){   返回putVal(散列(关键)、关键值,假的,真的);   }   最后一个int散列(对象键){   int h;   返回(关键==null) & # 63;0:(h=key.hashCode ()) ^ (h祝辞祝辞祝辞16);   }      

把方法调用了私有方法putVal,不过值得注意的是,关键的哈希值不是直接用的hashCode,最终的散列=(hashCode右移16)^ hashCode。

  

在将散列值映射为桶位置的时候,取的是散列值的低位部分,这样如果有一批关键的仅高位部分不一致,就会聚集的同一个桶里面。(如果桶数量比较少,关键是浮动类型,且是连续的整数,就会出现这种情况)。

  

执行插入的过程:

        V putVal (int散列,K键,V值,布尔>   公共V删除(对象键){   Nodee;   返回(e=removeNode(散列(关键),钥匙,null,假的,真的))==null & # 63;   空:e.value;   }      NoderemoveNode (int散列、对象关键对象的值,   布尔matchValue,布尔活动){   Node[]选项卡;Nodep;整数n,指数;//代码段1   如果((标签=表)!=零,,(n=tab.length)比;0,,   (p=选项卡(指数=(n - 1),哈希)!=null) {//代码段2:   Nodee节点=零;K K;V V;   如果(p。散列==散列,,   ((k=p.key)==关键| |(关键!=零,,key.equals (k))))   节点=p;//代码段3:   else if ((e=p.next) !=null) {//代码段3.1:   如果(p instanceof TreeNode)   节点=((TreeNode) p)。getTreeNode(散列键);   其他{//代码段3.2:   {做   如果(e。散列==散列,,   ((k=e.key)==关键| |   (钥匙!=零,,key.equals (k)))) {   节点=e;   打破;   }   p=e;   },((e=e.next) !=null);   }   }//代码段4:   如果(节点!=零,,(!matchValue | | (v=node.value)价值==| |   (价值!=零,,value.equals (v)))) {//代码段4.1:   如果节点instanceof TreeNode)   ((TreeNode)节点)。removeTreeNode(选项卡,这活动);//代码段4.2:   else if(节点==p)   选项卡(指数)=node.next;//代码段4.3:   其他的   p。下一个=node.next;   + + modCount;   ——大小;   afterNodeRemoval(节点);   返回节点;   }   }   返回null;   }

java基础类型源码解析之多角度讲HashMap