啊哈瞬间之tableSizeFor函数
导读:我记得在《编程珠玑》一书中,作者提到了总有一些优秀的编程思想会让人忍不住发出“啊哈”的声音,这有可能是叹为观止,也有可能是恍然大悟。
1. 简介
tableSizeFor是Java的hashmap/concurrenthashmap的源码中比较重要的一个函数,其功能是:返回一个比输入值大或相等的,离该值最近的2的整数次幂
。举例:输入值是5,则该函数返回值是8(2的3次幂),输入值是4,则返回4。说实话,在我真正理解这个函数之前,如果你把它的源码放到我面前,让我说出这个函数的功能,我可能真的无法说出答案。在我花时间理解之后,我是忍不住内心发出了“啊哈”的赞叹!
如果你感兴趣,可以先不看后面的介绍,然后对照我上面所说的功能,看看自己是如何实现的?
OK,如果你已经写好了,那让我们看看java原作者是怎么实现的吧?话不多说,先上源码,本文中使用的是JDK11的源码。
private static final int tableSizeFor(int c) {int n = -1 >>> Integer.numberOfLeadingZeros(c - 1);return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
2. 剖析过程
如果你看完上面的几行代码后瞬间就理解了,那么恭喜你,我已经献上了我的膝盖,后面也没必要继续看了。否则的话,我们就试着一起来理解一下吧~~
2.1 -1的二进制表示
- 取原码:00000000 00000000 00000000 00000001
- 求反码(逐位求反):11111111 11111111 11111111 11111110
- 得补码(反码+1):11111111 11111111 11111111 11111111
也就是说-1的二进制表示是:11111111 11111111 11111111 11111111
,事实上上面的过程就是求一个负数二进制表示方法的过程。
2.2 位运算
java中常见的位运算包括:按位与&、按位或|、按位非~、按位异或^,也包括>>(右移位),<<(左移位)。
右移位符号>> N通常理解为除以2的N次幂,左移<< N可理解为乘以2的N次幂。那>>>又是几个意思呢?看着也是移位。
- >>:带符号右移,正数右移后高位补0,负数右移后高位补1,因此4>>1 = 2 ,-4>>1 = -2。
- >>>:无符号右移,不管正数还是负数,右移后高位都补0。
因此,对于正数来说,二者返回值一样,但如果是负数,则相差很远,如果你是想实现除以2的效果,那么请用>>吧。
2.3 算法核心
核心在于用“二进制”来思考问题,而不是十进制,对于任意一个整数,换算为二进制之后(以5为例是0101,高位的0省略),那么比它大的2的整数次幂最小的一个值即是高一位置1,其他位置0(以5为例是1000,换算为二进制是8)。那么怎么实现这个想法呢?
作者巧妙的使用了-1进行>>>操作,右移的位数使用了Integer.numberOfLeadingZeros(c - 1),比如c是5,则0100(5-1)前面的0的位数是29,将-1>>>29位得到的是0111;然后再将结果+1,得到1000(8),就是我们期望的结果啦~
先减1再加1这个简直是神操作,既能刚好得到一个2的整数幂的值,而且能避免边界情况,即输入值本身就是2的整数幂的情况,比如输入值为4的时候,如果不减1操作,那么得到的就是8了。
好了,tableSizeFor就解析到这儿了,不知道你啊哈了没?
啊哈瞬间之tableSizeFor函数相关推荐
- 求最接近cap的2次幂(tableSizeFor函数的实现)
不比cap小的2次幂(HashMap中的tableSizeFor函数) // 初始化临界值的具体实现 static final int tableSizeFor(int cap) {int n = c ...
- 【面试】JAVA三年经验面试题
整理一下最近面试遇到过的问题,有一些想不起来了,希望能给大家一点帮助吧,也给自己留个底,嘿嘿,平时还是得多注意知识的积累,以及技术细节 - 1.JAVA基础类型各占几个字节? bit 字节 int 3 ...
- linux内核的反复--一切都是过程
1. ZERO_PAGE 2.6.24内核中剔除了ZERO_PAGE这个鸡肋,然而近期又准备添加近来,这样做的原因还是在于当初它为何被当成了鸡肋,当成鸡肋的原因就是当zero页面加入反向映射的时候会更 ...
- java map原理_Java HashMap底层原理分析
前两天面试的时候,被面试官问到HashMap底层原理,之前只会用,底层实现完全没看过,这两天补了补功课,写篇文章记录一下,好记性不如烂笔头啊,毕竟这年头脑子它记不住东西了哈哈哈.好了,言归正传,今天我 ...
- JAVA集合(四、ConcurrentHashMap)
参考自: https://javadoop.com/post/hashmaphttps://blog.csdn.net/lsgqjh/article/details/54867107https://w ...
- Java集合(一、HashMap)
参考: https://juejin.im/post/5b5bf507f265da0fa42ce89e 要点总结 1.HashMap内部数据元素(Map.Entry<key,value>) ...
- 深入理解HashMap(三): 关键源码逐行分析之构造函数
前言 系列文章目录 上一篇我们说明了HashMap的hash算法, 说到HashMap在构造时会自动将table设为2的整数次幂. 本篇我们就来聊聊HashMap的构造函数. 本文的源码基于 jdk8 ...
- C语言丨getch(),getche()和getchar()的区别
关于C语言中的getch(),getchar() getche()函数肯定十分困扰大家,今天将他们整理和大家一起分享. 1.getchar() 函数名:getchar() 头文件:stdio.h 功 ...
- C++坦克大战(新手)
程序流程图 根据流程图我把程序分位四部分: 第一部分:游戏设置初始化 :设置窗口名称,大小 :隐藏光标,切换输入法(控制台赶紧去输入法是中文的) :背景音乐设置 第二部分:游戏菜单设计,选择游戏模式 ...
最新文章
- DL-5 深度学习框架的对比
- 软件包管理 之 file.src.rpm 使用方法的简单介绍
- 详细介绍Python中的“魔术方法“__XXX___; 概述__str__()方法;__new__()方法; 三. __ new__ 和__init__的区别
- 拍摄中如何判断灰度等级_如何判断电力铁塔的电压等级?每个人都应知道
- 有没有一种让人很爽的学习方法?
- 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?...
- Java 异常处理机制
- 网络丢包诊断与分析的现实与理想
- Nginx教程(三) Nginx日志管理 (转)
- 循迹小车c语言程序51单片机,51单片机循迹小车Proteus仿真程序
- zmap扫描mysql_zmap使用笔记
- ORA-01045: user lacks CREATE SESSION privilege; logon denied
- 计算机鼠标右键的主要应用是什么原因,win7电脑桌面鼠标右键功能和作用|win7 64位桌面右键没反应,反应非常慢...
- 社交规则:饭后抢着买单到底是客气还是客套?大多并不是真心的
- ebs查看服务状态_监控您的卷状态 - Amazon Elastic Compute Cloud
- mac、parallel是什么
- html js左侧导航栏,js实现简单分页导航栏效果
- 第七周作业:注意力机制学习的part2
- 先锋录音系统服务器,先锋音讯IP电话云录音系统——全球首创
- 屏幕小于6英寸的手机_6英寸以内的小屏旗舰手机推荐,纯手感无敌!