Ready

HashMap为什么变成从尾部插入?

2019-04-01  本文已影响0人  packet

HashMap的源码比较多,不想粘贴了(也没有必要),这里只粘贴下重要常量。

 /**
  * 默认初始大小,值为16,要求必须为2的幂
  */
 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 
 /**
  * 最大容量,必须不大于2^30
  */
 static final int MAXIMUM_CAPACITY = 1 << 30;

/**
 * 默认加载因子,值为0.75
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
 * hash冲突默认采用单链表存储,当单链表节点个数大于等于8时,会转化为红黑树存储
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * hash冲突默认采用单链表存储,当单链表节点个数大于8时,会转化为红黑树存储。
 * 当红黑树中节点少于等于6时,则转化为单链表存储
 */
static final int UNTREEIFY_THRESHOLD = 6;

/**
 * hash冲突默认采用单链表存储,当单链表节点个数大于8时,会转化为红黑树存储。
 * 但是有一个前提:要求数组长度大于等于64,否则不会进行转化
 */
static final int MIN_TREEIFY_CAPACITY = 64;

HashMap默认采用数组+单链表方式存储元素,当元素出现哈希冲突时,会存储到该位置的单链表中。但是单链表不会一直增加元素,当元素个数超过8个时,会尝试将单链表转化为红黑树存储。但是在转化前,会再判断一次当前数组的长度,只有数组长度大于等于64才处理。否则,进行扩容操作。此处先提到这,后续会有详细的讲解。




512插入以后






HashMap在1.7和1.8之间的变化:
1.7采用数组+单链表,1.8在单链表超过一定长度后改成红黑树存储
1.7扩容时需要重新计算哈希值和索引位置,1.8并不重新计算哈希值,巧妙地采用和扩容后容量进行&操作来计算新的索引位置。
1.7插入元素到单链表中采用头插入法,1.8采用的是尾插入法。
HashMap在jdk1.7中采用头插入法,在扩容时会改变链表中元素原本的顺序,以至于在并发场景下导致链表成环的问题。而在jdk1.8中采用尾插入法,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了。

参考:HashMap之元素插入HashMap为何从头插入变成尾插入

上一篇 下一篇

猜你喜欢

热点阅读