HashMaphashmap = new HashMap<>();//初始化加载因子 DEFAULT_LOAD_FACTOR=0.75public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}hashmap.put("name","wj");public V put(K key, V value) { return putVal(hash(key), key, value, false, true);}
//计算hash值static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab;//Node节点数组 Node p; //单个Node节点,Node是一个单项链表 int n, i; //transient Node [] table,起始为null if ((tab = table) == null || (n = tab.length) == 0) { //初始化Node数组,n = 16 n = (tab = resize()).length; } //根据i = (n - 1) & hash计算出索引值,n为table.length if ((p = tab[i = (n - 1) & hash]) == null) { //如果该Node数组在该索引值没有值,则直接添加 tab[i] = newNode(hash, key, value, null); } else { //如果该Node数组在该索引值已存在值 Node e; K k; //p是Node数组在该索引的节点 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) { //如果新值与旧值的key的hash值相同,并且key的地址相同或者key进行equals比较相等,就更新value值 e = p; } else if (p instanceof TreeNode) { e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value); } else { //发生了hash冲突,循环遍历该Node链表 for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { //遍历到链表最后了,直接挂载上去 p.next = newNode(hash, key, value, null); //TREEIFY_THRESHOLD == 8,如果该Node链表的长度超过8了,准备红黑树化 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { //遍历过程中发现有key的hash值相等,并且key的地址相同或者equals相等,直接更新value值,结束遍历 break; } p = e; } } if (e != null) { //oldValue原索引Node节点的value值 V oldValue = e.value; //onlyIfAbsent 为 false if (!onlyIfAbsent || oldValue == null) { //将节点Node的value更新为最新的值 e.value = value; } afterNodeAccess(e); //返回旧的值 return oldValue; } } ++modCount; //threshold为table.length * 0.75 if (++size > threshold) { //执行扩容 resize(); } afterNodeInsertion(evict); return null;}
//Node是HashMap里的一个内部类,实现了Entry接口,Entry接口是Map接口的内部接口,Node是一个单向链表static class Nodeimplements Map.Entry { final int hash; final K key; V value; Node next; Node(int hash, K key, V value, Node next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }}
//Node数组扩容机制final Node[] resize() { //transient Node [] table,起始为null Node [] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { //第一次put时,oldCap == 0,DEFAULT_INITIAL_CAPACITY = 16 //newCap == 16,newThr == 0.75 * 16 == 12 newCap = DEFAULT_INITIAL_CAPACITY; 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; @SuppressWarnings({"rawtypes","unchecked"}) //newCap初始化为16 Node [] newTab = (Node [])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode )e).split(this, newTab, j, oldCap); else { // preserve order Node loHead = null, loTail = null; Node hiHead = null, hiTail = null; Node next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab;}
总结:
- 加载因子0.75是在创建HashMap实例的时候确定的
- Node
table[] 是在第一次put时才会初始化大小,起始为16,每次进行put操作时size会+1,发生hash冲突进行的链表操作不会加一,当size超过 table.length * 加载因子 就会触发扩容,进行数组拷贝,长度变为原数组的两倍,并且会重新计算索引值,也就是说原索引为6的Node节点扩容后索引值并不一定还是6 - 对于key的hash值相同,并且满足key的地址相同或者equals相同,会将旧的value值更新,并返回旧的value值
- 发生hash冲突时,采用遍历Node链表进行插入,遍历过程中有满足3的会执行3的操作,没有则插到链表尾
- 在链表长度超过8时,会进行是否树化的判断,只有当Node数组的长度大于64才会进行红黑树化,否则会直接触发扩容