Java8 HashMap 扩容之后旧元素存放位置

123 阅读1分钟

根据源码可看出,java 在扩容的时候会新建一个新的 Node<K,V>[] 来存放扩容之后的值,并将旧有的Node数组置空;

至于旧有值移动到新的节点的时候存放于哪个节点,Java 是根据 (e.hash & oldCap) == 0 来判断的:

① 等于0时,则将该节点放到新数组时的索引位置等于其在旧数组时的索引位置,记为低位区链表lo开头-low;

② 不等于0时,则将该节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度,记为高位区链表hi开头high.

举例说明:

1、当e.key =  7 ,旧有数组oldCap长度为16的时候:
     根据  (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16) ; 且当key 为 int 的时候 key.hashCode 返回的就是key本身可以算出来 e.hash = 7
     
     1、因为 oldCap = 16,此时,若要  (e.hash & oldCap) == 0 ,则 e.hash 的二进制形式中与对应oldCap的二进制的1的位置一定为0,其他位置的可以随意,这样即可保证结果为0;
   
     2、而 7 & 16 = 111&10000 = 0, 所以值为7的节点放在新数组时的索引位置等于其在旧数组时的索引位置;

 2、当e.key17 ,旧有数组oldCap长度为16的时候:
     
     1、同理可以算出 17 & 16 = 10001 & 10000 = 10000, 所以值为17的节点等于其在旧数组时的索引位置再加上旧数组长度;