HashMap
1.7(数组+链表)
1.数组长度:2的n次方,初始化长度不够会计算大于并最接近自定义长度的2的n次方的数值,例如3=>22, 11=>24, 12=>24, 17=>25
2.定位数组下标:时间复杂度O(n),通过hash位运算取余([key的hash] &[ 数组计算后的长度(2^n)-1])定位到数组下标位置(O(1)),可能会有hash冲突,冲突的hash使用链表保存(O(n))
ps:位运算为什么是要2n-1,是因为2n的二进制数只有一个1,其它都是0,例如16(0000 0000 0001 0000),导致与运算后的结果只有两种
(0000 0000 0001 0000=>16,0000 0000 0000 0000=>0),导致数据空出太多空间,而且超出最大下标,所以-1保证低位 都是1,高位都是0(0000 0000 0000 1111=>15),那不管与运算任何值,高位都是0,低位01之间随机,那不就是0~15之间了吗(牛逼)
3.数组扩容:扩容的阀值限定为数组长度*0.75(0.75是空间与时间的折中值),扩容的长度也是2^n(创建新数组),扩容是把旧数组的值移到新的数组,那就要重新算hash,扩容后的数组中的链表顺序会倒过来,具体可以查看源码,简单来讲就是,1,先把头部移到新数组的槽位,2,然后再把下个节点的尾部指针指向新数组的对应槽位上的节点(上个操作1所移动的那个节点),3,最后就是把新数组的下标指针指向2所在的节点,那就相当于原本新数组下标指向是2的变成了3,2就变成了3的下一个节点
ps:由于线程是不安全的,倒序会很容易形成闭环,那就是无法在往这个链表上put数据了
>1.7(数组+链表+红黑树
1.数组长度:同上
2.定位数据下标:同上, hash冲突后,当链表长度大于8(TREEIFY_THRESHOLD)时转成红黑树(前提要数组容量>=64(MIN_TREEIFY_CAPACITY),<64就扩容)
3.数组扩容:高低位转移拆分方式,避免链环死锁