HashMap源码原理详解

HashMap源码原理详解

背景:最近2019年7月25日和同事闲聊,简单给我来了点模拟面试,其中一个点就是HashMap,情况老惨了。

1、什么时候扩容?怎么扩容?

/**
* 返回一个比给定整数cap大且最接近的2的幂次方整数
* 比如初始化cap为16/17/18等,则tableSizeFor返回的是32
* cap:haspmap中数组长度
*/
static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

以上代码表示返回cap依次分别与“右移1位、2位、4位、8位、16位之后的值”异或后的值,那为什么非要最后无符号右移16位呢,因为int类型四个字节,一个字节8位,总共32位。

下面举例详细讲:

例如cap的二进制数: 00000000 00000000 00000000 00010000

无符号右移一位: 00000000 00000000 00000000 00001000

异或: 00000000 00000000 00000000 00011000

无符号右移两位: 00000000 00000000 00000000 00000110

异或: 00000000 00000000 00000000 00011110

无符号右移四位: 00000000 00000000 00000000 00000001

异或: 00000000 00000000 00000000 00011111

无符号右移八位异或: 不变

无符号右移16位异或: 不变

从上面的例子可以看出,tableSizeFor(cap)是把cap的二进制数中第一个出现的1后面的所有0全部变成1,最后return的时候再加上1

即:

如果 2的N-1次方 <= cap < 2的N次方 , 则tableSizeFor(cap) 为2的N次方-1+1

而且最坏的情况下,需要变31个0仅仅需要5次,时间复杂度为logn(因为每次异或产生的有效位为只2的次幂级的)。

所以现在我们就可以解释为什么只需要右移异或到16即可:16位已经操作好的数和16位没操作好的数进行异或,就会产生32位操作好的数——一定可以把32位int型操作完。上面的例子也可以看出如果cap很小,则不需要执行所有的右移异或就已经拿到了应有的结果。16位右移异或是针对cap很大的情况,为了覆盖所有的int操作。

(不明白可以亲自测试下0010000 00000000 00000000 00000000)这种二进制数(随便举的例子)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值