关于jdk:JDK源码分析Integer

9次阅读

共计 2345 个字符,预计需要花费 6 分钟才能阅读完成。

一. 根本形容

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 的哈希办法

@Override
public 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

正文完
 0