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) 收藏 举报
浙公网安备 33010602011771号