java基礎-HashMap

jdk7的HashMap實現的思路比較簡單,就是一個Entry數組,數組中每一個Entry都是一個鏈表的起點(表頭)。數組

 

 1     public V put(K key, V value) {
 2         if (table == EMPTY_TABLE) {
 3             inflateTable(threshold);
 4         }
 5         //若是key爲null,則將該entry放在第0位
 6         if (key == null)
 7             return putForNullKey(value);
 8         int hash = hash(key);
 9         int i = indexFor(hash, table.length);
10         //檢查第i位的鏈表中是否存在該key,若是存在,則將原value替換爲新value
11         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
12             Object k;
13             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
14                 V oldValue = e.value;
15                 e.value = value;
16                 e.recordAccess(this);
17                 //並返回舊value
18                 return oldValue;
19             }
20         }
21 
22         modCount++;
23         //若是不存在則將entry添加在第i位鏈表表頭,若是(size >= threshold) && (null != table[bucketIndex])爲真(threshold=capacity*loadFactor),還會涉及resize(擴容,resize(2 * table.length);)操做
24         addEntry(hash, key, value, i);
25         return null;
26     }

 jdk7的hash函數app

 1     final int hash(Object k) {
 2         int h = hashSeed;
 3         if (0 != h && k instanceof String) {
 4             return sun.misc.Hashing.stringHash32((String) k);
 5         }
 6 
 7         h ^= k.hashCode();
 8 
 9         // This function ensures that hashCodes that differ only by
10         // constant multiples at each bit position have a bounded
11         // number of collisions (approximately 8 at default load factor).
12         h ^= (h >>> 20) ^ (h >>> 12);
13         return h ^ (h >>> 7) ^ (h >>> 4);
14     }

 

jdk7中的HashMap存在一個問題,若是key的hash值都映射到同一個桶中,hashMap的查找就會退化成順序查找,這會極大影響查找性能(對插入性能無影響)。jdk8爲了解決這一問題,對HashMap進行了一些改進,當一個桶中的鏈表長度大於內設閾值(8)時,就會將該桶的鏈表樹化(treeify),即將鏈表轉變爲一個紅黑樹(其他位置的鏈表不會受到影響)。函數

 

 

1     public V put(K key, V value) {
2         return putVal(hash(key), key, value, false, true);
3     }

 jdk8的hash函數性能

1     static final int hash(Object key) {
2         int h;
3         //hashCode返回一個int共32位,最終就是高16位保持原樣,低16位與高16亦或後造成新的低16位。這樣作是爲了防止hashCode低位全0的狀況,在映射後(hash&(table.length-1))就會彙集在第0位。
4         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
5     }

 

 

 1     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 2                    boolean evict) {
 3         //tab就是table,p是前驅節點,n是table長,i是key的index
 4         Node<K,V>[] tab; Node<K,V> p; int n, i;
 5         if ((tab = table) == null || (n = tab.length) == 0)
 6             n = (tab = resize()).length;
 7         //若是第i位尚沒有節點,則直接插入
 8         if ((p = tab[i = (n - 1) & hash]) == null)
 9             tab[i] = newNode(hash, key, value, null);
10         else {//第i位已經存在節點的狀況
11             Node<K,V> e; K k;
12             //首節點的key與即將插入的key相同
13             if (p.hash == hash &&
14                 ((k = p.key) == key || (key != null && key.equals(k))))
15                 e = p;
16             //若是首節點是TreeNode,說明該位是一棵紅黑樹,直接插入
17             else if (p instanceof TreeNode)
18                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
19             //遍歷鏈表進行替換或插入
20             else {
21                 for (int binCount = 0; ; ++binCount) {
22                 //若是p.next爲null,則插入到鏈表末端
23                 if ((e = p.next) == null) {
24                         p.next = newNode(hash, key, value, null);
25                         //若是鏈表長度大於TREEIFY_THRESHOLD(8,不可設置)則樹化
26                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
27                             treeifyBin(tab, hash);//樹化該位的鏈表爲一棵紅黑樹
28                         break;
29                     }
30                     //若是找到相同的key,則直接跳出,後續會更新value
31                     if (e.hash == hash &&
32                         ((k = e.key) == key || (key != null && key.equals(k))))
33                         break;
34                     p = e;
35                 }
36             }
37             //更新value
38             if (e != null) { // existing mapping for key
39                 V oldValue = e.value;
40                 if (!onlyIfAbsent || oldValue == null)
41                     e.value = value;
42                 afterNodeAccess(e);
43                 return oldValue;
44             }
45         }
46         ++modCount;
47         if (++size > threshold)
48             resize();
49         afterNodeInsertion(evict);
50         return null;
51     }
相關文章
相關標籤/搜索