1. 程式人生 > >源碼分析八( hashmap工作原理)

源碼分析八( hashmap工作原理)

swa checked ++ ble sign nan 數字 als IV

首先從一條簡單的語句開始,創建了一個hashmap對象:

Map<String,String> hashmap = new HashMap<String,String>();

調用hashmap類無參數構造方法,使用默認轉載因子,

1 public HashMap() {
2         this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
3     }

默認裝載因子只有在構造器不指定的情況下使用

1 /**
2      * The load factor used when none specified in constructor.
3 */ 4 static final float DEFAULT_LOAD_FACTOR = 0.75f;

hashmap還有三個重載的構造方法,分別是:

有裝載因子入參的構造方法

1 public HashMap(int initialCapacity) {
2         this(initialCapacity, DEFAULT_LOAD_FACTOR);
3     }

有初始化容器容量以及裝載因子的構造方法

 1 public HashMap(int initialCapacity, float loadFactor) {
 2         //如果初始容量小於0,則拋出非法初始化容量異常
3 if (initialCapacity < 0) 4 throw new IllegalArgumentException("Illegal initial capacity: " + 5 initialCapacity); 6 //如果初始容量大於最多容量,則容量為最多容量 7 if (initialCapacity > MAXIMUM_CAPACITY) 8 initialCapacity = MAXIMUM_CAPACITY;
9 //如果裝載因子不大於0或者裝載因子不是數字,則拋出裝載因子非法異常 10 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 11 throw new IllegalArgumentException("Illegal load factor: " + 12 loadFactor); 13 this.loadFactor = loadFactor; 14 //根據初始化容量計算hashmap的閾值容量(hashmap真正的容量,必須是2的次方) 15 this.threshold = tableSizeFor(initialCapacity); 16 }

計算hashmap的容量

 1 // 根據給定的目標容量,計算一個2的次方
 2     static final int tableSizeFor(int cap) {
 3         int n = cap - 1;
 4         n |= n >>> 1;
 5         n |= n >>> 2;
 6         n |= n >>> 4;
 7         n |= n >>> 8;
 8         n |= n >>> 16;
 9         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
10     }

有參數map的構造方法:

1 public HashMap(Map<? extends K, ? extends V> m) {
2             this.loadFactor = DEFAULT_LOAD_FACTOR;
3             putMapEntries(m, false);
4      }

將map復制一份到本地,這個復制如果對於數值型則為數值,對於引用型則為地址

 1 final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
 2         int s = m.size();
 3         //原來map的長度大於0處理
 4         if (s > 0) {
 5             if (table == null) { // pre-size
 6                 //根據實際數量計算需要多大的容量
 7                 float ft = ((float) s / loadFactor) + 1.0F;
 8                 int t = ((ft < (float) MAXIMUM_CAPACITY) ? (int) ft : MAXIMUM_CAPACITY);
 9                 //如果預估容量大於現有容量,則需要根據預估容量計算一個2的次方數
10                 if (t > threshold)
11                     threshold = tableSizeFor(t);
12             }
13             //如果實際容量大於閾值則需要擴容
14             else if (s > threshold)
15                 resize();
16             //擴容之後,將m的key和value復制一份到本地
17             for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
18                 K key = e.getKey();
19                 V value = e.getValue();
20                 putVal(hash(key), key, value, false, evict);
21             }
22         }
23     }

 1 //第一次調用初始化或者擴容
 2     final Node<K,V>[] resize() {
 3         //首次調用時為null,則oldCap為0 | 擴容時,
 4         Node<K,V>[] oldTab = table;
 5         int oldCap = (oldTab == null) ? 0 : oldTab.length;
 6         int oldThr = threshold;
 7         int newCap, newThr = 0;
 8         //擴容時,如果目前容量已經超過最多容量,那麽默認值為int最大,否則容量為現在2倍
 9         if (oldCap > 0) {
10             if (oldCap >= MAXIMUM_CAPACITY) {
11                 threshold = Integer.MAX_VALUE;
12                 return oldTab;
13             }
14             else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
15                      oldCap >= DEFAULT_INITIAL_CAPACITY)
16                 newThr = oldThr << 1; // double threshold
17         }
18         //初始化時newCap = oldThr = threshold
19         else if (oldThr > 0) // initial capacity was placed in threshold
20             newCap = oldThr;
21         else {               // zero initial threshold signifies using defaults
22             newCap = DEFAULT_INITIAL_CAPACITY;
23             newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
24         }
25         //初始化時newThr=newCap * loadFactor
26         if (newThr == 0) {
27             float ft = (float)newCap * loadFactor;
28             newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
29                       (int)ft : Integer.MAX_VALUE);
30         }
31         threshold = newThr;
32         @SuppressWarnings({"rawtypes","unchecked"})
33         //初始化時,創建一個長度為threshold的Node數組,然後返回
34             Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
35         table = newTab;
36         if (oldTab != null) {
37             for (int j = 0; j < oldCap; ++j) {
38                 Node<K,V> e;
39                 if ((e = oldTab[j]) != null) {
40                     oldTab[j] = null;
41                     if (e.next == null)
42                         newTab[e.hash & (newCap - 1)] = e;
43                     else if (e instanceof TreeNode)
44                         ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
45                     else { // preserve order
46                         Node<K,V> loHead = null, loTail = null;
47                         Node<K,V> hiHead = null, hiTail = null;
48                         Node<K,V> next;
49                         do {
50                             next = e.next;
51                             if ((e.hash & oldCap) == 0) {
52                                 if (loTail == null)
53                                     loHead = e;
54                                 else
55                                     loTail.next = e;
56                                 loTail = e;
57                             }
58                             else {
59                                 if (hiTail == null)
60                                     hiHead = e;
61                                 else
62                                     hiTail.next = e;
63                                 hiTail = e;
64                             }
65                         } while ((e = next) != null);
66                         if (loTail != null) {
67                             loTail.next = null;
68                             newTab[j] = loHead;
69                         }
70                         if (hiTail != null) {
71                             hiTail.next = null;
72                             newTab[j + oldCap] = hiHead;
73                         }
74                     }
75                 }
76             }
77         }
78         return newTab;
79     }

源碼分析八( hashmap工作原理)