一. 根本形容
java.lang.Integer
是最罕用的Java类型之一,然而恐怕很少有人会去留神这个撑持起整个Java世界的小小基石。
Integer
类的申明是 public final class Integer extends Number implments Comparable<Integer>
,咱们能够发现Integer
类是不能被继承的。
Integer
的外围字段是private final int value
,这个字段代表着Integer
对象所示意的整数值,final
修饰符意味着Integer
是immutable
即不可变的。
还有一个乏味的中央在Integer
的哈希办法
@Overridepublic int hashCode() { return Integer.hashCode(value);}public static int hashCode(int value) { return value;}
Integer
的哈希办法间接返回了整数示意
二. reverse办法
reverse办法的实现很有意思
public static int reverse(int i) { i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555; i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333; i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f; i = (i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24); return i; }
咱们一步步剖析,首先是第一行i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555
留神了啊,很多人对16进制不敏感,16进制的0x5
开展成二进制就是0101
,0x55555555
就是01010101010101010101010101010101
,那么代码前半部分(i & 0x55555555) << 1
的性能是只保留整数i的偶数位(从0开始计数)并左移一位,代码后半局部(i >>> 1) & 0x55555555
的性能是只保留整数i的奇数位
第一行代码合起来所实现的性能就是将i的二进制每2位划为一组,并将组内的位替换地位。
相似的,0x3
开展成二进制就是0011
,第二行代码的性能就是将i的二进制每4位划为一组,并将组内的前两位和后两位替换地位。
看起来就像这样:
初始 1234 | 5678
第一趟 2143 | 6587
第二趟 4321 | 8765
显然第三行代码的作用就是将二进制每8位划为一组,将组内前四位和后四位替换地位。
最初一行就更好了解了,int
类型在Java里是用4个字节示意的,i << 24)
将i的最初一个字节放到第一个字节的地位,(i & 0xff00) << 8
将i的第三个字节放到第二个字节的地位,(i >>> 8) & 0xff00
将i的第二个字节放到第三个字节的地位,i >>> 24
将i的第一个字节放到最初的地位
三. bitCount办法
bitCount办法的实现很精妙,初看非常难懂,而最难懂的正是第一行
public static int bitCount(int i) { i = i - ((i >>> 1) & 0x55555555); i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); i = (i + (i >>> 4)) & 0x0f0f0f0f; i = i + (i >>> 8); i = i + (i >>> 16); return i & 0x3f; }
又是相熟的0x55555555
,(i >>> 1) & 0x55555555
将i的奇数位剥离进去并右移一位,真正让人难以了解的是这个减法,着实难以了解它的目标。为了讲述不便,咱们用4位二进制来展现
假如心愿求1101
的1'
位数量,通过第一行代码则变成了1101 - 0100
,留神看啊,如果每2位划分为一组,咱们有11 - 01 = 10
和01 - 00 = 01
,最初失去的后果刚好是每2位一组里的1'
位数量,是不是很微妙11
右移取奇数位失去01
,11 - 01 = 10
即蕴含2个1'
10
右移取奇数位失去01
,10 - 01 = 01
即蕴含1个1'
01
右移取奇数位失去00
,01 - 00 = 01
即蕴含1个1'
00
右移取奇数位失去00
,00 - 00 = 00
即蕴含0个1'
我是真的服了,这种法则都能发现到。或者这大概率不是JDK作者原创的,然而这个办法真的是让我忍不住喊一句——喵喵!
上面贴个图展现一下第一步
后续的代码都是建设在第一行的根底上的,通过第一行代码后,咱们晓得将i的二进制每2位划为一组,则这个组里的二进制数就示意了该组的1的数量,前面咱们要做的就是将这些数加起来天然就失去整个二进制所蕴含的1的数量
再聊一下这段代码的细节之处吧,兴许各位没留神,然而我留神到,第三行代码是先相加再用掩码清空,第四行和第五行则齐全没有用上掩码,这是为什么?
废话不多说,间接上图好了
第四行和第五行不须要掩码的起因是一样的,因为不会造成溢出啊
四. IntegerCache
置信大家面试的时候肯定有被问到过这种问题:Integer a = 10; Integer b = 10
,a == b 是否成立?
默认状况下Integer
会在加载时将[-128, 127]区间里的数(蕴含边界)都生成Integer对象缓存起来,如果代码里应用主动装箱的赋值形式,即Integer x = 常量值
的模式,且常量值在[-128, 127]内则会应用缓存中的Integer
对象
源码正文上说缓存的大小能够通过JVM的启动参数-XX:AutoBoxCacheMax=<size>
来批改,我本人尝试了一下,联合源码正文我发现这个参数无奈影响到下界,区间下界是写死的-128,而且这个参数批改的是上界,而不是它的名字表白的整个缓存大小,所以理论的缓存大小该当是XX:AutoBoxCacheMax - (-128) + 1