HashMap源码解析

 

HashMap简介

在jdk1.8中,HashMap采用的是数组+链表/红黑树的实现形式,其是线程不安全的。HashMap中可以存储键值为null的数值。HashMap有两个比较重要的参数,初始容量(initialCapacity)和负载因子(loadFactory),初始值分别为16和0.75。当HashMap中的元素个数达到当前容量乘以负载因子的乘积时,HashMap将会进行扩容,执行resize和rehash操作。

 

HashMap重要参数解析

1. 初始容量

/**

* The default initial capacity - MUST be a power of two.

*/

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

 

初始容量:16,在注释中,jdk特别标注了初始容量必须是2的n次幂,这是什么原因呢?我们可以通过源码找找这个答案。

为什么数组大小一定要是2的幂

 

put方法

 

图2

 

在put方法中,当我们调用put(key,value)方法,首先是计算key的hash值,然后通过hash值计算在数组中的下标位置,其计算下标的代码为 (n - 1)& hash。n在629行代码中将其赋值为了HashMap的数组大小,即其计算方式为HashMap的数组长度减1再跟哈希值进行按位与运算。

当数组长度是2的n次方,数组长度减1后它的二进制数就是都是1的值,此时对哈希值进行按位与操作得到的下标才是分布均匀的,如果不是2的n次幂,那么减1后二进制的值有的位就是0,此时该位与哈希值进行按位与操作就一直是0,就会导致有些哈希桶的值一直都是空的,值分布不均匀。

例如,假设我们的数组大小是16,减1后的值其二进制数低4位为 1111,高28位全是0。此时一个32位的哈希值与其进行按位与运算,假设该哈希值为0110110.......1101001,与1111进行按位与运算后得到的值为1001,那么1001即为数组下标的值。

当n = 2的幂时,(n - 1) & hash 等价于 hash % n。这里又有一个疑问了,既然是计算数组下标,为什么不直接用求余计算呢?仔细思考下可以发现,求余操作在这里有两个缺点:哈希值的范围是在 -2^31 ~ 2^31 -1这个范围内,它是有负数的,由于我们数组下标肯定都是要求正整数的,但是负数进行求余得到的还是负数,这是第一个缺点。第二个缺点是求余操作比起位运算来说还是较慢的。因此HashMap中计算下标采用了位运算。

2. 最大初始容量

/**

* The maximum capacity, used if a higher value is implicitly specified

* by either of the constructors with arguments.

* MUST be a power of two <= 1<<30.

*/

static final int MAXIMUM_CAPACITY = 1 << 30;

最大初始容量不能大于2的30次方。因为int类型最大值是2^31 - 1,达不到2^31,所以最大初始容量只能取2^30。

 

3. 负载因子

/**

* The load factor used when none specified in constructor.

*/

static final float DEFAULT_LOAD_FACTOR = 0.75f;

负载因子的默认值为0.75,在源码中有这么一行注释解释了其为什么选择0.75的默认值:

 

图像3

大概意思是说默认负载因子(0.75)在时间和空间成本之间提供了一个很好的折衷方案。较高的值会减少空间开销,但会增加查找成本(在HashMap类的大多数操作中都得到了体现,包括get和put )。

 

4. 链表转成红黑树的阈值

/**

* 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
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值