ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java HashMap 扩容过程分析

2020-04-02 22:03:57  阅读:260  来源: 互联网

标签:扩容 Java HashMap newTab 链表 newCap hash null oldCap


 

  1 final Node<K, V> resize(){
  2 
  3     // 用于存储重新散列后的数组
  4     Node<K, V>[] newTab;
  5     
  6     // 如果原来的数组是空的,则resize执行的是初始化操作,而不是扩容操作
  7     if(table == null){
  8         // 初始容量为16
  9         int cap = DEFAULT_CAPACITY;// 1<<<4
 10 
 11         // 初始的加载因子为0.75,即容量使用到3/4时就要再次扩容
 12         loadFactor = DEFAULT_LOADFACTOR;
 13 
 14         // 设置扩容阈值
 15         threshold = (int)(cap * loadFactor);
 16 
 17         newTab = (Node<K, V>[])(new Node[cap]);
 18         return newTab;
 19     }
 20 
 21     // ... 省略了细节处理,例如容量到达最大值时应该怎么办,本程序段主要讲述扩容流程
 22 
 23     // 如果原来的数组不为空,则先扩容,再把原来的数据重新散列到新的扩容后的数组中
 24     int oldCap = table.length;
 25     int newCap = oldCap << 1;
 26     threshold = newCap * loadFactor;
 27     newTab = (Node<K, V>[])(new Node[newCap]);
 28 
 29     // 循环遍历原来的数组,进行重新散列
 30     for(int i = 0; i < table.length; i++){
 31 
 32         if(table[i] == null){
 33             continue;
 34         }
 35 
 36         Node<K,V> e = table[i];
 37         table[i] = null;
 38 
 39         // 数组中每个元素下都是一个链表
 40         // 如果链表只有一个元素,那么直接将其放到新位置
 41         if(e.next == null){
 42             newTab[e.hash & (newCap-1)] = e;
 43             continue;
 44         }
 45 
 46         // 如果链表中有多个元素,则需要将其分成两个链表
 47         // 为什么是两个链表呢?因为当 hash&(oldCap-1) == i 时,
 48         // hash&(newCap-1) 只会有两个取值:i 和 i+oldCap
 49         // 证明:
 50         //    假设 oldCap = 16 = 0b10000
 51         //    则   newCap = 16 <<< 1 = 0b100000
 52         //    则   oldCap - 1 = 0b1111
 53         //         newCap - 1 = 0b11111
 54         //    则 hash&(oldCap-1) 与 hash&(newCap-1) 只有 从又向左数第五位不同
 55         //    又因为 0b10000 = oldCap 
 56         //    所以   hash&(newCap-1) == hash&(oldCap-1) == i 
 57         //          或 hash&(newCap-1) == hash&(oldCap-1)+oldCap == i+oldCap
 58 
 59         // 链表1:放在原处,即 hash&(newCap-1) = hash&(oldCap-1) = i
 60         Node<K, V> hiHead, hiTail;
 61         // 链表2:放在 i+oldCap处,即hash&(newCap-1) = hash&(oldCap-1)+oldCap = i+oldCap
 62         Node<K, V> loHead, loTail;
 63         do{
 64             // 将原来链表中的元素分类放到链表1、2中
 65             
 66             // 如果散列值与原来一样(i)
 67             if((e.hash & (oldCap-1)) == (e.hash & (newCap-1))){
 68                 if(loHead == null){
 69                     loHead = e;
 70                 } else {
 71                     loTail.next = e;
 72                 }
 73                 loTail = e;
 74             } else {
 75                 // 如果散列值与原来不一样(i+oldCap)
 76                 if(hiHead == null){
 77                     hiHead = e;
 78                 } else {
 79                     hiTail.next = e;
 80                 }
 81                 hiTail = e;
 82             }
 83             e = e.next;
 84         } while(e != null);
 85 
 86         if(hiHead != null){
 87             hiTail.next = null;
 88             
 89             // 放在新位置
 90             newTab[i+oldCap] = hiHead;
 91         }
 92         if(loHead != null){
 93             loTail.next = null;
 94 
 95             // 放在原处
 96             newTab[i] = loHead;
 97         }
 98     }
 99 
100     return newTab;
101 }

 

标签:扩容,Java,HashMap,newTab,链表,newCap,hash,null,oldCap
来源: https://www.cnblogs.com/cbhe/p/12623296.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有