一. 根本形容

java.lang.Integer是最罕用的Java类型之一,然而恐怕很少有人会去留神这个撑持起整个Java世界的小小基石。

Integer类的申明是 public final class Integer extends Number implments Comparable<Integer>,咱们能够发现Integer类是不能被继承的。

Integer的外围字段是private final int value,这个字段代表着Integer对象所示意的整数值,final修饰符意味着Integerimmutable即不可变的。

还有一个乏味的中央在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开展成二进制就是01010x55555555就是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位二进制来展现
假如心愿求11011'位数量,通过第一行代码则变成了
1101 - 0100,留神看啊,如果每2位划分为一组,咱们有11 - 01 = 1001 - 00 = 01,最初失去的后果刚好是每2位一组里的1'位数量,是不是很微妙
11右移取奇数位失去0111 - 01 = 10 即蕴含2个1'
10右移取奇数位失去0110 - 01 = 01 即蕴含1个1'
01右移取奇数位失去0001 - 00 = 01 即蕴含1个1'
00右移取奇数位失去0000 - 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