1.数据结构分析
JDK8之前的版本:数组+链表 (下面引用别人博客的一张图,图片原博客)
数组中是Entry,Entry中next存有下一个Entry中的引用,比如A先存在table[0]中 一会又来了个B也要放到table[0]中,就会变成B放table[0]中,B中的next放A的引用。
存放是时候根据key进行hash计算来找到该键对应到数组中存储的索引位置,尽量均匀的分布到数组的各个位置中,取值时候也要根据hash计算出存储的位置,然后遍历所在位置下的链表,意义比较找到值,比较是通过equals的hashCode来比较的。所以如果要用某个对象来作为存储的key时一定要根据自己的需求去重写equals、hashCode方法。
JDK8:当链表长度超过8,链表将转为红黑树存储。(一样是引用别人的图,图片原博客)
数组中是Node,每个Node都是链表的头结点。
2.扩容分析
数组肯定是会涉及到扩容问题的。
capacity :如果初始化的时候不指定大小的话,默认是16,最大容量MAXIMUM_CAPACITY是1 << 30也就是2的30次方。
threshold:阀值,当存储数量大于阀值的时候就会触发扩容,threshold = capacity * loadFactor(capacity为2的倍数)。
loadFactor:负载因子,代表table的填充度有多少,默认是0.75。
从上面可以看出HashMap的扩容并不是存储满了的时候才扩容的,在利用了百分之七十五的时候就开始扩容了,通过查看源码的resize方法,得知达到扩容标准后,数组容量和阀值会增加到原来的2倍,并将当前数组中的元素全部复制过去,扩容是个比较耗资源的操作。
该篇文章并没有详细分析,只做总结几个重要特点,详细分析可点进上面图片原博客,已经有大佬分析的很到位了。