1. 存储的数据结构不同
JDK1.7及之前以数组+链表的形式存储元素。
JDK1.8及之后以数组+链表+红黑树的形式存储元素。(默认长度为16)
为什么这样这样做?
因为当链表的长度过长的时候,查询的效率就直线下降,所以在JDK1.8之后将其设计为当链表的长度达到一定的阈值的时候,就会将链表结构转换为红黑树结构,红黑树是一种自平衡的二叉搜索树,提高查询效率。
2. 插入数据的方式不同
JDK1.7及之前采用的是链表头部插入数据。
JDK1.8及之后采用的是链表尾部插入数据。
- 扩容后转换数据不需要遍历到链表的尾部再插入。
- 最近添加的元素可能马上就要被获取,头插的方式只需要遍历到链表的头部就能匹配到了。
- 扩容后链表可能会倒序,并发扩容可能会产生循环链
3. hash运算不同
JDK1.7及之前计算hash运算多
JDK1.8及之后计算hash运算少
4. 扩容时调整的数据方式不同
JDK1.7及之前扩容后数据会根据hash值重新计算索引的位置,然后将数据存放到对应的位置上。
JDK1.8及之后扩容后数据要么等于原来的位置,要么等于原来的位置+旧容量。
5. 扩容方式不同
JDK1.7及之前首先检查是否需要进行扩容,再插入数据(扩容为原来的两倍)
- 存放新的元素时,已经存在的元素的个数必须大于等于阈值。
- 存放新的元素时,与已经存在的元素发生hash碰撞(新元素key计算hash值换算出来的数组下标的位置上已存在元素),满足这两个条件就会进行扩容。
JDK1.8及之后首先插入数据,再检查是否需要扩容
- 当数组的容量未达到64的时候,则以两倍进行扩容。
- 当数组的容量达到64之后,若链表的元素大于等于8个时,则将链表结构转换为红黑树结构。
- 删除元素后,当红黑树中的节点小于等于6个时,则将红黑树结构转换回链表结构。
- 当红黑树的节点不少于32个的时候,才会继续进行扩容,扩容机制更加优化。