HashMap底层结构、扩容机制

一、底层结构

在JDK8之后,HashMap由之前的“数组+链表”转为“数组+链表+红黑树

类似于这种结构

数组即左边一列,链表即横着相连的那部分

那红黑树在哪呢?当链表的长度大于等于8时,为了将查找时间复杂度由n降为logn,这个链表就会转化为红黑树

但上面都是很基础的内容,下面讲两个比较不常见的知识点

1、链表长度大于等于8时,一定会转为红黑树吗?

在HashMap源码中有这样几个变量

/*
The bin count threshold for using a tree rather than list for a bin. 
Bins are converted to trees when adding an element to a bin with at least this many nodes. 
*/
static final int TREEIFY_THRESHOLD = 8;

/*
The smallest table capacity for which bins may be treeified.
(Otherwise the table is resized if too many nodes in a bin.)
*/
static final int MIN_TREEIFY_CAPACITY = 64;


final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        // 省略代码
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
    ...
}

TREEIFY_THRESHOLD = 8说明确实定义了一个“树化的临界值“,且这个值为8

但在treeifyBin()这个函数中,并不是直接把链表转化为红黑树,而是先检查数组容量是否小于MIN_TREEIFY_CAPACITY这个值,如果小于,会先进行扩容。这样做的目的是尽量避免将链表转为树这种较为复杂的结构,所以通过扩容的方式减少哈希冲突,尝试将这个结点分配到数组的其他位置上

如果数组容量大于等于64了,那么就只能将其转为红黑树了

2、当红黑树结点数小于8时,会不会转回链表?

/*
The bin count threshold for untreeifying a (split) bin during a
resize operation.
*/
static final int UNTREEIFY_THRESHOLD = 6;

直接说结论:会,但不是立刻转回,而是要等到下一次resize()时检验结点数与UNTREEIFY_THRESHOLD的关系,如果小于等于6,就可以转回

二、扩容机制

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

static final float DEFAULT_LOAD_FACTOR = 0.75f;

其实很简单,就是数组初始容量capacity为(1 << 4) = 16,加载因子load_factor为0.75,当已经使用的容量等于capacity * load_factor时,就会调用resize()函数,将最大容量扩充为原来的2倍

目的:减少哈希冲突,提高存取效率

为什么加载因子等于0.75?

因为load_factor太大会导致哈希冲突增加,存取效率低

太小会导致数组的利用率低,存放的数据会很分散

load_factor的默认值为0.75f是官方给出的一个比较好的临界值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值