HashMap源码__tableSizeFor方法解析
tableSizeFor(int cap)方法返回不小于指定参数cap的最小2的整数次幂,具体是怎么实现的呢?看源码!
/**
* Returns a power of two size for the given target capacity.
*/
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;
}
1)为什么cap要减一?
2)|=是什么?
3)>>>又是什么?
4)为什么要返回n+1
先解释一下"|"是什么
这里的“|”是叫做位或运算,百度百科这样解释到:按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的2个二进位有一个为1时,结果位就为1。当参与运算的是负数时,参与两个数均以补码出现。
假设使用8位来储存数字,下面用一张图来说明下位或运算: 8|1
十进制8的二进制表示为图中的A : 00001000
十进制1的二进制表示为图中的B : 00000001
从图中可以看出A从右向左第四个位为1,B从右向左第一个位为1,其余位都为0,因此结果的第一个和第四个位都为1,结果就是00001001转换为十进制就是9,因此 8 | 1 = 9 。
A |= B 的意思就是 A = A | B
>>>表示无符号右移
也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
假设使用8位来储存数字,下面用一张图来说明下右移运算: 8>>>1
8>>>1表示将8右移一位,如图所示:右移后高位也就是蓝色部分补0,低位也就是红色部分直接舍弃,结果就变成了0000100转换为十进制就是4,因此 8 >>> 1 = 4
明白了>>>和 | 的作用就可以来解释上面的源码了,
假设cap=9,n = cap - 1 = 8( 至于为什么需要减一待会儿再说)
n |= n >>> 1; 也就是 n = n | (n>>>1)
在java中int占4个字节也就是32位,
因此8的二进制表示为:00000000......00001000 ( 中间省略16个0)
8>>>1的结果是: 00000000......00000100
8 |= 8>>>1 的结果是: 00000000......00001100
结果转换为十进制为:12
12>>>2的结果是:00000000......00000011
12 |= 12>>>1的结果是:00000000......00001111
结果转化为十进制为:15
15>>>4的结果是:00000000......00000000
15 |= 15>>>4的结果是:00000000......00001111
结果转化为十进制为:15
15>>>8的结果为:00000000......00000000
15 |= 15>>>8的结果为:00000000......00001111
结果转化为十进制为:15
15>>>16的结果为:00000000......00000000
15 |= 15>>>16的结果为:00000000......00001111
结果转化为十进制为:15
最后返回 n+1 也就是 16
上面的操作其实就是把 8 的二进制表示 00000000......00001000,把 1 后面的 0 全部变成了000000000......0001111.
为什么 n+1 之后就是2的整数次幂呢?
看一下二进制是如何转换为十进制的就明白了
二进制转换为十进制:
设一个n位的二进制的位数从右至左依次为0~n位,那么从0~n位分别乘于2的n次幂的和即为该二进制的十进制形式。
00000001 的十进制表示为 1 * 2^0 = 1
00000001 加一之后就变成了 00000010 转换为十进制就是 0*2^0 + 1*2^1 = 0 + 2 = 2
00000011 的十进制表示为 1*2^0 + 1*2^1 = 3
00000011 加一之后就变成了00000100 转换为十进制就是 0*2^0 + 0*2^1 + 2*2^2 = 0 + 0 + 4 = 4
00000111 的十进制表示为 1*2^0 + 1*2^1 + 1*2^2 = 7
00000111加一之后就变成了00001000 转换为十进制就是 0*2^0 + 0*2^1 + 0*2^2 + 1*2^3 + = 0 + 0 + 0 + 8 = 8
为什么要对cap进行减一操作呢?
这样就可以避免当cap已经是2的整数次幂时,再对cap进行一次求次幂操作,比如:cap=16,如果没有减一结果就会变成32,而16已经符合HashMap的要求了.
最新文章
- Ubuntu[1]安装Vesta Control Panel
- FMDB简单封装和使用
- ecshop 默认图处理
- jdk版本及编译版本导致服务器部署UnsupportedClassVersionError错误
- centos rabbitmq
- Thread和Service应用场合的区别
- android123 zhihuibeijing 新闻中心-新闻 页签 ViewPagerIndicator实现
- mysql-创建函数,存储过程以及视图
- 【转】Devexpress使用之:GridControl控件(合并表头)
- PS图片
- 从头来之【图解针对虚拟机iOS开发环境搭建】 (转)
- php:修改NetBeans默认字体
- hdu 3045 Picnic Cows(斜率优化DP)
- 我的iOS-App
- python基础一之课后作业:编写登录接口
- 动态代理之: com.sun.proxy.$Proxy0 cannot be cast to 问题
- iOS-AFN Post JSON格式数据
- hdu 1004 颜色与数字(map水题)
- UICollectionView在初始化的时候移动到某个距离
- 在iOS中将string转成UTF-8编码
热门文章
- nodejs redis遇到的一个问题解决
- DUI-Windows消息机制要点(34篇)
- Hadoop —— 集群环境搭建
- (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
- mysql group_concat的长度问题
- Asp.net HttpClient Proxy(Fiddler)
- 字节跳动Java研发面试99题(含答案):JVM+Spring+MySQL+线程池+锁
- 12 | 从0到1:你的第一个GUI自动化测试
- CentOS 7出现Failed to start firewalld.service: Unit is masked的解决办法和firewalld 防火墙开关
- 【HDU - 1495】非常可乐