HashMap

 

 hash

static final int hash(Object key) {
        int h;
        //^异或运算  二进制不同时,则为1,相同时为0 比如1010^1100=0110
        //>>>无符号右移  不带符号向右移动二进制数,移动后前面统统补0
        //hash高16位与自己的低16位异或
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

resize

/**
     * 扩容(一倍)
     */
    final HashMap.Node<K, V>[] resize() {
        //旧tab
        HashMap.Node<K, V>[] oldTab = table;
        //旧tab的length
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        //旧阈值
        int oldThr = threshold;
        //新tab的length和阈值
        int newCap, newThr = 0;
        //旧tab的length大于0
        if (oldCap > 0) {
            //大于等于Integer.MAX_VALUE
            if (oldCap >= MAXIMUM_CAPACITY) {
                //阈值设置为Integer.MAX_VALUE
                threshold = Integer.MAX_VALUE;
                //返回旧tab
                return oldTab;
            }
            //tab扩展两倍
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                    oldCap >= DEFAULT_INITIAL_CAPACITY)
                //阈值扩展两倍
                newThr = oldThr << 1; // double threshold
        }
        //旧tab的length为零,但是并不是第一次初始化
        else if (oldThr > 0) // initial capacity was placed in threshold
            //新tab的length设置为阈值,此处使得newThr为零
            newCap = oldThr;
            //旧tab的length为零,第一次初始化
        else {               // zero initial threshold signifies using defaults
            //设置新tab的length为默认值 16
            newCap = DEFAULT_INITIAL_CAPACITY;
            //设置新tab的阈值  默认负载因子*默认初始化大小  16*0.75=12
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }

        //如果新阈值为零,重新设置阈值
        if (newThr == 0) {
            //默认阈值
            float ft = (float) newCap * loadFactor;
            //边界值处理,设置新阈值
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ?
                    (int) ft : Integer.MAX_VALUE);
        }

        //此时设置全局变量阈值为局部变量新阈值
        threshold = newThr;
        //创建新tab数组
        @SuppressWarnings({"rawtypes", "unchecked"})
        HashMap.Node<K, V>[] newTab = (HashMap.Node<K, V>[]) new HashMap.Node[newCap];
        //设置全局变量数组为局部变量新数组
        table = newTab;
        if (oldTab != null) {
            //将旧数组数据复制到新数组中
            for (int j = 0; j < oldCap; ++j) {
                HashMap.Node<K, V> e;
                //将数组元素赋值e
                if ((e = oldTab[j]) != null) {
                    //防止内存泄漏进行置空
                    oldTab[j] = null;
                    //tab中node只有一个节点
                    if (e.next == null)
                        //&二进制位与运算 两个数都为1则为1,否则为0
                        //key的hash与新tab的length减一做位与运算,
                        //此处hash通过hash(Object key)获取,可以让tab的分布更加均匀,减少hash冲突的可能性。
                        //直接赋值给新tab数组对应位置
                        newTab[e.hash & (newCap - 1)] = e;
                        //如果是红黑树
                    else if (e instanceof HashMap.TreeNode)
                        //将node放入红黑树
                        ((HashMap.TreeNode<K, V>) e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        HashMap.Node<K, V> loHead = null, loTail = null;
                        HashMap.Node<K, V> hiHead = null, hiTail = null;
                        HashMap.Node<K, V> next;
                        do {
                            next = e.next;
                            //(e.hash & oldCap)等于零,那node的位置为原来的位置
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    //node的位置没有发生倒置的情况
                                    loHead = e;
                                else
                                    loTail.next = e;
                                
                                loTail = e;
                            }
                            //不等于零,那node的位置是原来的位置加上原来数组的长度
                            else {
                                if (hiTail == null)
                                    //node的位置没有发生倒置的情况
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                
                                hiTail = e;
                            }
                        } while ((e = next) != null);


                        if (loTail != null) {
                            loTail.next = null;
                            //key落在新tab的位置为旧tab的原来的位置
                            newTab[j] = loHead;
                        }

                        if (hiTail != null) {
                            hiTail.next = null;
                            //扩容一倍,key落在新的tab中原来的位置加上以前的tab长度
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

putVal

 1  final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 2                    boolean evict) {
 3         HashMap.Node<K, V>[] tab;//局部变量存放table,进行扩容存在线程安全问题。
 4         HashMap.Node<K, V> p;//临时的node用作数据转换
 5         int n;//tab的长度
 6         int i;
 7 
 8         //如果tab是null,或者大小为0
 9         //tab进行扩容
10         if ((tab = table) == null || (n = tab.length) == 0)
11             n = (tab = resize()).length;
12         //找到key对应的tab的位置,如果是null
13         if ((p = tab[i = (n - 1) & hash]) == null)
14             //创建node放入对应的tab数组中
15             tab[i] = newNode(hash, key, value, null);
16             //如果对应的tab已经有node对象
17         else {
18             HashMap.Node<K, V> e;
19             K k;
20 
21             //node的hash与key的hash相等并且node的key和key内存地址或者值相同。
22             if (p.hash == hash &&
23                     ((k = p.key) == key || (key != null && key.equals(k))))
24                 //把现有的node赋值给e
25                 e = p;
26                 //如果现在的node是红黑树。
27             else if (p instanceof HashMap.TreeNode)
28                 //将对应的key和value放入红黑树中。
29                 e = ((HashMap.TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
30             else {
31                 //遍历链表
32                 for (int binCount = 0; ; ++binCount) {
33                     //到达尾部
34                     if ((e = p.next) == null) {
35                         //创建key,value的node放到链表尾部。
36                         p.next = newNode(hash, key, value, null);
37                         //如果链表的长度大于等于阈值-1
38                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st  转换类型的默认值默认是8,也就是链表的长度大于等于7,就会转为红黑树。
39                             //链表转红黑树。链表的查询时间复杂度是O(n),红黑树的是O(log n),提升查询效率。为什么是8,根据泊松分布链表长度是8出现的的可能性较小,这样可以减少类型转换的频率。
40                             treeifyBin(tab, hash);
41                         //执行完退出循环
42                         break;
43                     }
44 
45                     //找到node的key的hash与key的hash相等并且node的key和key内存地址或者值相同。
46                     if (e.hash == hash &&
47                             ((k = e.key) == key || (key != null && key.equals(k))))
48                         //满足条件退出循环。
49                         break;
50 
51                     //继续判断下一个node值,将e赋值给p
52                     p = e;
53                 }
54             }
55             //map中存在对应的key
56             if (e != null) {
57                 V oldValue = e.value;
58                 if (!onlyIfAbsent || oldValue == null)
59                     //把原有的值覆盖
60                     e.value = value;
61 
62                 //hashmap用不到这个方法
63                 afterNodeAccess(e);
64                 return oldValue;
65             }
66         }
67 
68         //记录map修改值得次数
69         ++modCount;
70 
71         //如果map的key的数量大于阈值-1时,进行扩容。
72         if (++size > threshold) // 
73             //扩容,当前map的元素个数大于 tab的长度*负载因子 -1 ,默认值情况也就是 当元素个数大于   16*0.75-1=11 也是当12时进行扩容。此时的扩容时已经把值放入map之后的事,先插入后扩容。
74             resize();
75         //hashmap用不到这个方法
76         afterNodeInsertion(evict);
77         return null;
78     }

posted on 2020-01-04 23:13  seesea_bky  阅读(152)  评论(0)    收藏  举报