java基础-HashMap

Posted holoyong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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函数

 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     }

 

以上是关于java基础-HashMap的主要内容,如果未能解决你的问题,请参考以下文章

Java基础:HashMap假死锁问题的测试分析和总结

hashmap冲突的解决方法以及原理分析:

包含不同片段的HashMap(或ArrayList)

大厂面试必问!HashMap 怎样解决hash冲突?

Java基础——HashMap设计原理&实现分析

Java基础教程:HashTable与HashMap比较