一直都是对HashMap的底层及扩容原理都没有很好的理解,所以就决定重新对HashMap的底层原理重新来梳理梳理。
HashMap这个扩容原理真的是众说纷纭,感觉就没有一个较为清楚,原来只知道的HashMap当链表的长度大于8 并且数组的长度大于64 链表才会转换成红黑树。但是一直没有去自我验证,今天我就来验证验证,此次我们使用的是JDK1.8:
/**
* @author acoffee
* @create 2021-08-23 11:02
*/
public class Test {
public static void main(String[] args) {
HashSet set = new HashSet();
for (int i = 1; i <= 12; i++) {
//我们在这排deBug
set.add(new Student(i));
}
}
}
class Student {
private int age;
public Student(int age) {
this.age = age;
}
//重写hashCode 为了使所有的值挂在一个链表上
@Override
public int hashCode() {
return 100;
}
}
我们开始debug
我们可以看到此时table为空,这就意味着 当我们去创建Map的时候他是不会在底层创建长度为16的数组的。我们继续
从上述结果我们可以清楚的看到,当我我们第一次添加的时候,我们的数组长度就变成了16 ,并且我们添加的数据通过Hashcode计算在索引为4的位置。
因为接下来我们添加的hash值都是一样的,就都会挂在一个链子上,我们不再过多赘述,我们直接添加 8 个数据使 链表长度 到8,来看结果。
通过上图我们可以清楚的看到此时链表已经到8,我们继续添加
从上图可以看出我们将链表长度添加到9,此时从我们的框起来的位置可以看出,他还是一个链表,并没有变成树,但是当我们将debug框往下翻的时候,我们发现数组的长度变成了32。我们继续添加
此时我们发现数组的长度变成了64,而我们原本存放在4索引位置的链表 变到索引为36的位置,而且此时还是链表。我们继续添加:
这个时候我们就发现数组的长度不在改变了,但是如图所示Node结点变成了TreeNode结点,到此链表就转换成了红黑树。
所以在这里我们得出结论 HashMap中只有当链表的长度大于8并且数组的长度大于等于64 链表才会转换成红黑树。
还有就是Map第一次put底层才会创建一个长度为16 的数组。
完整过程:
当我们第一次调用HashMap的时候,它不会在底层创建一个长为16 的数组,而是当我们第一次put 的时候它就会创建一个长度为16的数组,我们一直拿数据往同一链表上挂(由于找hash值相同数据很难,所以 上述我们用了重写hashCode的方法) 直至长度为8,此时数组的长度还是16,我们发现这个长度为8的链表并没有转换成红黑树,而当我们继续往链表上添加数据,数组会扩容至原来的两倍(32),链表长度也会增长至9,继续往链表上添加数据,链表会继续增长至10,数组扩容为64,这个时候就满足了转红黑树的条件,继续添加,我们可以清楚的看到链表变成了红黑树。