hashmap转红黑树的阈值为8_HashMap数据结构剖析

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 21:04   4761   0

书接上文,HashMap源码分析上文书对hashmap的源码做了一个简单的解析,这回我们来说一下HashMap的数据结构问题。

上文中说到HashMap的基础结构一个初始容量为16的数组,加载因子是0.75,也就是容量使用到12的时候会触发扩容机制,扩容后的容量为原来的2倍。

但这并不是说超过12个元素就会扩容,其实这里容量为16的数组并不只是一个简单的数组结构,而是数组在链表的结构。类似于下面图中这样的一个结构:

2f8a8dc0298c16c34b8cf49f63140f09.png

数组中的每个索引中包含的元素可能是多个,也就是可能>=0个元素。那么这个索引的值是怎么计算的呢?我们在源码可以看到

public V put(K key, V value) {

return putVal(hash(key), key, value, false, true);

}

其中hash函数的代码如下:

static final int hash(Object key) {

int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

即通过上面做对计算出key的hash值,然后我们在putVal()中可以看到如下的代码:

if ((tab = table) == null || (n = tab.length) == 0)

n = (tab = resize()).length;

if ((p = tab[i = (n - 1) & hash]) == null)

tab[i] = newNode(hash, key, value, null);

..........

其中关键代码是这句:

i = (n - 1) & hash

即,是通过key的hash值和容器的大小减1,两者进行与运算,获取容器数组下标。这里使用与运算,其实蕴含了一个隐藏条件,即数组的大小n,必须是2的n次方,否则,计算出来的下标值i是无法覆盖这个范围[0, n-1]的。这就是为什么每次扩容都是*2的原因。

而如果这个链表可以无限延长,那么毫无疑问会造成查询数据的性能问题,于是JDK1.8引入的红黑树,上文中提到的由链表转红黑树的阈值是8,也就是如果链表的长度到8就会转变成树结构。以此来解决链表过长而引发的性能问题。红黑树的存储结构大概如下:

2830f344932203feb6e693ed60e1a926.png

这里顺便推荐一个数据结构可视化的网站https://www.cs.usfca.edu/~galles/visualization,可以直观的了解红黑树和其它数据结构,也可以对比其它树结构,应该就能明白为何HashMap选用红黑树而不是其它的树型结构。这里就不再赘述。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP