HashMap初始容量总结,彻底吃透位运算,简历立马多项熟练( 二 )

运行结果F:softwareJavajdk1.8.0_121binjava.exe "-javaagent:D:IntelliJ IDEA 2019.1.4libidea_rt.jar=51640:D:IntelliJ IDEA 2019.1.4bin" -Dfile.encoding=UTF-8 -classpath F:softwareJavajdk1.8.0_121jrelibcharsets.jar;F:softwareJavajdk1.8.0_121jrelibdeploy.jar;F:softwareJavajdk1.8.0_121jrelibextaccess-bridge-64.jar;F:softwareJavajdk1.8.0_121jrelibextcldrdata.jar;F:softwareJavajdk1.8.0_121jrelibextdnsns.jar;F:softwareJavajdk1.8.0_121jrelibextjaccess.jar;F:softwareJavajdk1.8.0_121jrelibextjfxrt.jar;F:softwareJavajdk1.8.0_121jrelibextlocaledata.jar;F:softwareJavajdk1.8.0_121jrelibextnashorn.jar;F:softwareJavajdk1.8.0_121jrelibextsunec.jar;F:softwareJavajdk1.8.0_121jrelibextsunjce_provider.jar;F:softwareJavajdk1.8.0_121jrelibextsunmscapi.jar;F:softwareJavajdk1.8.0_121jrelibextsunpkcs11.jar;F:softwareJavajdk1.8.0_121jrelibextzipfs.jar;F:softwareJavajdk1.8.0_121jrelibjavaws.jar;F:softwareJavajdk1.8.0_121jrelibjce.jar;F:softwareJavajdk1.8.0_121jrelibjfr.jar;F:softwareJavajdk1.8.0_121jrelibjfxswt.jar;F:softwareJavajdk1.8.0_121jrelibjsse.jar;F:softwareJavajdk1.8.0_121jrelibmanagement-agent.jar;F:softwareJavajdk1.8.0_121jrelibplugin.jar;F:softwareJavajdk1.8.0_121jrelibresources.jar;F:softwareJavajdk1.8.0_121jrelibrt.jar;D:ideastudyspacespring_studyspring-studyspring-study-proxytargetclasses;E:softwareMavenRepositoryorgspringframeworkspring-webmvc3.2.0.RELEASEspring-webmvc-3.2.0.RELEASE.jar;E:softwareMavenRepositoryorgspringframeworkspring-context3.2.0.RELEASEspring-context-3.2.0.RELEASE.jar;E:softwareMavenRepositoryorgspringframeworkspring-aop3.2.0.RELEASEspring-aop-3.2.0.RELEASE.jar;E:softwareMavenRepositoryorgspringframeworkspring-core3.2.0.RELEASEspring-core-3.2.0.RELEASE.jar;E:softwareMavenRepositorycommons-loggingcommons-logging1.1.1commons-logging-1.1.1.jar;E:softwareMavenRepositoryorgspringframeworkspring-web3.2.0.RELEASEspring-web-3.2.0.RELEASE.jar;E:softwareMavenRepositoryaopallianceaopalliance1.0aopalliance-1.0.jar;E:softwareMavenRepositoryorgspringframeworkspring-expression3.2.0.RELEASEspring-expression-3.2.0.RELEASE.jar;E:softwareMavenRepositoryorgspringframeworkspring-beans3.2.0.RELEASEspring-beans-3.2.0.RELEASE.jar;E:softwareMavenRepositorycomalibabafastjson1.2.47fastjson-1.2.47.jar com.shiguang.service.DemotableSizeFor方法返回值:16Process finished with exit code 0这个时候返回的是16,2的4次方,也是大于且最接近9的2的n次方的数 。那么tableSizeFor(int cap)方法是如何实现这个功能的呢?
代码分析首先我们先理解三个位运算符“|” 或运算举例:00010010------------------或运算(对应二进制位同是0时等于0,只要有1等于1)0011“|=” 或等于举例:a |= b 就相当于 a = a | b">>>" 无符号右移举例:1001 >>> 21001---------- 1001无符号右移2位0010 01了解以上位运算符,我们便可以轻松明白这个方法的原理了
用户指定HashMap初始数组容量 cap=9,进入tableSizeFor(int cap)方法1 [执行代码]:int n = cap - 1; n=8[最后我们再解释为什么这里要cap-1]2 [执行代码]: n |= n >>> 1;首先计算n >>> 1------------------------------------------------------二进制十进制描述------------------------------------------------------0000 10008初始值----------------------n >>> 10000 0100~~0~~4结果接着计算 n|n >>> 10000 100080000 01004-------------------------------或运算0000 110012结果3 [执行代码]: n |= n >>> 2;[注意]此时的n=0000 1100首先计算n >>> 20000 110012-------------------------n >>> 20000 0011~~00~~3结果接着计算 n|n >>> 20000 1100120000 00113--------------------------------或运算0000 111115结果4 [执行代码]: n |= n >>> 4;[注意]此时的n=0000 1111首先计算 n >>> 40000 111115-------------------------n >>> 40000 0000~~1111~~0结果接着计算 n|n >>> 40000 1111150000 00000--------------------------------或运算0000 1111155 [执行代码]: n |= n >>> 8;0000 111115结果6 [执行代码]: n |= n >>> 16;0000 111115结果----------------------------------------------------我们不难发现规律start 0000 1000end0000 1111初始值经过两轮[无符号右移]加[或运算]后已将最高二进制位上的1后面的所有二进制位都变成了1我们知道int类型占4个字节,也就是32位, 这样任意一个int类型的数进来经过这5轮[无符号右移]加[或运算],最高二进制位上的1后面的所有二进制位都会变成1接着我们执行这个方法的最后一行代码return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;显然此时我们的n=15,在[0,MAXIMUM_CAPACITY]这个区间内,所以return n + 1;系统设置HashMap集合的初始容量 cap=16;那int n = cap - 1这行代码又有什么用呢?
显然这行代码是为了防止用户给定的初始值就等于2的n次方,如果用户给定值是8,而tableSizeFor(int cap)方法里没有cap - 1这行代码,那么方法的返回值就变成了16,这样就造成了不必要的内存浪费  。


推荐阅读