导读:我记得在《编程珠玑》一书中,作者提到了总有一些优秀的编程思想会让人忍不住发出“啊哈”的声音,这有可能是叹为观止,也有可能是恍然大悟。

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函数相关推荐

  1. 求最接近cap的2次幂(tableSizeFor函数的实现)

    不比cap小的2次幂(HashMap中的tableSizeFor函数) // 初始化临界值的具体实现 static final int tableSizeFor(int cap) {int n = c ...

  2. 【面试】JAVA三年经验面试题

    整理一下最近面试遇到过的问题,有一些想不起来了,希望能给大家一点帮助吧,也给自己留个底,嘿嘿,平时还是得多注意知识的积累,以及技术细节 - 1.JAVA基础类型各占几个字节? bit 字节 int 3 ...

  3. linux内核的反复--一切都是过程

    1. ZERO_PAGE 2.6.24内核中剔除了ZERO_PAGE这个鸡肋,然而近期又准备添加近来,这样做的原因还是在于当初它为何被当成了鸡肋,当成鸡肋的原因就是当zero页面加入反向映射的时候会更 ...

  4. java map原理_Java HashMap底层原理分析

    前两天面试的时候,被面试官问到HashMap底层原理,之前只会用,底层实现完全没看过,这两天补了补功课,写篇文章记录一下,好记性不如烂笔头啊,毕竟这年头脑子它记不住东西了哈哈哈.好了,言归正传,今天我 ...

  5. JAVA集合(四、ConcurrentHashMap)

    参考自: https://javadoop.com/post/hashmaphttps://blog.csdn.net/lsgqjh/article/details/54867107https://w ...

  6. Java集合(一、HashMap)

    参考: https://juejin.im/post/5b5bf507f265da0fa42ce89e 要点总结 1.HashMap内部数据元素(Map.Entry<key,value>) ...

  7. 深入理解HashMap(三): 关键源码逐行分析之构造函数

    前言 系列文章目录 上一篇我们说明了HashMap的hash算法, 说到HashMap在构造时会自动将table设为2的整数次幂. 本篇我们就来聊聊HashMap的构造函数. 本文的源码基于 jdk8 ...

  8. C语言丨getch(),getche()和getchar()的区别

    关于C语言中的getch(),getchar() getche()函数肯定十分困扰大家,今天将他们整理和大家一起分享. 1.getchar() 函数名:getchar() 头文件:stdio.h 功  ...

  9. C++坦克大战(新手)

    程序流程图 根据流程图我把程序分位四部分: 第一部分:游戏设置初始化 :设置窗口名称,大小 :隐藏光标,切换输入法(控制台赶紧去输入法是中文的) :背景音乐设置 第二部分:游戏菜单设计,选择游戏模式 ...

最新文章

  1. DL-5 深度学习框架的对比
  2. 软件包管理 之 file.src.rpm 使用方法的简单介绍
  3. 详细介绍Python中的“魔术方法“__XXX___; 概述__str__()方法;__new__()方法; 三. __ new__ 和__init__的区别
  4. 拍摄中如何判断灰度等级_如何判断电力铁塔的电压等级?每个人都应知道
  5. 有没有一种让人很爽的学习方法?
  6. 虚析构函数? vptr? 指针偏移?多态数组? delete 基类指针 内存泄漏?崩溃?...
  7. Java 异常处理机制
  8. 网络丢包诊断与分析的现实与理想
  9. Nginx教程(三) Nginx日志管理 (转)
  10. 循迹小车c语言程序51单片机,51单片机循迹小车Proteus仿真程序
  11. zmap扫描mysql_zmap使用笔记
  12. ORA-01045: user lacks CREATE SESSION privilege; logon denied
  13. 计算机鼠标右键的主要应用是什么原因,win7电脑桌面鼠标右键功能和作用|win7 64位桌面右键没反应,反应非常慢...
  14. 社交规则:饭后抢着买单到底是客气还是客套?大多并不是真心的
  15. ebs查看服务状态_监控您的卷状态 - Amazon Elastic Compute Cloud
  16. mac、parallel是什么
  17. html js左侧导航栏,js实现简单分页导航栏效果
  18. 第七周作业:注意力机制学习的part2
  19. 先锋录音系统服务器,先锋音讯IP电话云录音系统——全球首创
  20. 屏幕小于6英寸的手机_6英寸以内的小屏旗舰手机推荐,纯手感无敌!

热门文章

  1. 求1+2+…+n的和不大于1000的最大自然数n
  2. 数据库的内连接和外连接
  3. 计算机控制系统是闭环还是开环,计算机控制系统复习题及答案
  4. 数学竞赛辅导陈启浩pdf_2020年数学建模竞赛备赛利器送你
  5. dnspy调试神器在IIS中无源码调试c#程序
  6. HTK搭建大词汇量连续语音识别系统(一)
  7. 开机自动启动宽带连接
  8. Fedora-i3折腾笔记
  9. Win10 MySQL5.7中文乱码问题
  10. 【BZOJ1003】【ZJOI2006】物流运输trans 最短路预处理+动态规划