上次咱们曾经对String类源码做了一个简略的总结,感兴趣的小伙伴能够去看一下啃碎JDK源码(一):String,明天来看看Java的Integer包装类。

先来看看Integer实现了哪些接口

public final class Integer extends Number implements Comparable<Integer> {

能够看到Integerfinal润饰,代表不可被继承,继承Number类实现Comparable接口。

private final int value;public static final int MIN_VALUE = 0x80000000;//最大值public static final int MAX_VALUE = 0x7fffffff;//最小值public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

能够看出应用了int类型的value来存储值,并且定义了Integer的最大值为2^31-1,最小值为-2^31Integer的根本数据类型为int

先来看一下Integer的两个构造函数:

public Integer(int value) {    this.value = value;}public Integer(String s) throws NumberFormatException {    this.value = parseInt(s, 10);}

那么这个parseInt办法是干啥用的呢?

办法parseInt(String s,int radix)的目标是输入一个十进制数。

比方:parseInt(1010,2)
意思就是:输入2进制数1010在十进制下的数。

咱们平时用到Integer.parseInt("123");其实默认是调用了int i =Integer.parseInt("123",10);

上面是源码:

public static int parseInt(String s, int radix)                throws NumberFormatException    {        /*         * WARNING: This method may be invoked early during VM initialization         * before IntegerCache is initialized. Care must be taken to not use         * the valueOf method.         */        if (s == null) {            throw new NumberFormatException("null");        }        //判断基数是否在 2~36之间        if (radix < Character.MIN_RADIX) {            throw new NumberFormatException("radix " + radix +                                            " less than Character.MIN_RADIX");        }        if (radix > Character.MAX_RADIX) {//36            throw new NumberFormatException("radix " + radix +                                            " greater than Character.MAX_RADIX");        }        int result = 0;        boolean negative = false;//是否为正数,默认为false        int i = 0, len = s.length();        int limit = -Integer.MAX_VALUE;        int multmin;        int digit;        if (len > 0) {            char firstChar = s.charAt(0);            if (firstChar < '0') { // Possible leading "+" or "-"                if (firstChar == '-') {//如果是正数,negative赋值为true,限度变为int的最小值                    negative = true;                    limit = Integer.MIN_VALUE;                } else if (firstChar != '+')                    throw NumberFormatException.forInputString(s);                if (len == 1) // Cannot have lone "+" or "-"                    throw NumberFormatException.forInputString(s);                i++;            }            /**multmin避免数据溢出             *如果是负数就是-2,147,483,64             *如果是正数就是-2,147,483,64 **/            multmin = limit / radix;            while (i < len) {                // Accumulating negatively avoids surprises near MAX_VALUE                //获取字符转换成对应进制的整数                digit = Character.digit(s.charAt(i++),radix);                if (digit < 0) {                    throw NumberFormatException.forInputString(s);                }                if (result < multmin) {                    throw NumberFormatException.forInputString(s);                }                result *= radix;                if (result < limit + digit) {                    throw NumberFormatException.forInputString(s);                }                result -= digit;            }        } else {            throw NumberFormatException.forInputString(s);        }        return negative ? result : -result;    }

valueOf

接下来来看一个比拟经典的问题,看上面代码:

Integer a = 100;Integer b = 100;Integer c = 200;Integer d = 200;System.out.println(a == b);System.out.println(c == d);

你认为这里是四个不同的对象,那么输入应该都是flase?

不,输入后果为:

true
false

通过javap -c/javap -verbose 命令能够查看字节码;红色圈圈里就是咱们jdk5之后的根本类型的主动包装的字节码实现,能够看出,此处是调用了Integer.valueOf(..)办法的:说白了就是Integer a = 100 等价于Integer a = Integer.valueOf(100)

JDK1.5之后,java提供了主动装箱和主动拆箱的性能。主动装箱也就是调用了Integer类的一个静态方法valueOf办法,那咱们来看看源码是如何实现的:

看看IntegerCache是个什么货色:

能够看到IntegerCache是一个动态外部类,low的值曾经写死-128,而high的值由你的虚拟机决定sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"),既然是一个参数也就意味着你能够动静设置。而后在循环中将low - high之间数字的装箱后办法cache[]这个Integer类型的数组中。这样就实现了缓存。

因为当咱们调用valueOf办法时传入-128到127之间的数字时,Integer会给咱们返回同样的对象,记住这一点当前面试的时候也能够和面试官吹吹牛逼了!

接下来咱们来看看Integer实现的equalshashcodetoString等办法:

equals 和 hashcode

public boolean equals(Object obj) {    if (obj instanceof Integer) {        return value == ((Integer)obj).intValue();    }    return false;}

能够看到它会先判断类型是否合乎,而后进行拆箱比拟操作。

看下hashcode办法:

@Overridepublic int hashCode() {    return Integer.hashCode(value);}public static int hashCode(int value) {    return value;}

能够看到hashcode间接返回自身的int值。

toString

IntegertoString办法 是我认为一个比拟乏味的中央:

看下toString(int i)源码:

在下面用到了stringSize办法,就是求这个Integer数的长度,咱们来看看他是如何实现的:

能够看到这段代码在计算Integer数长度时,构建了一个一维数组,而后拿x与数组每个值进行比拟。

还有一个getChars办法是获取数值对应的字符串,其中有两个中央应用了十分奇妙的形式来进行除法运算和取余运算。在计算机中,a/ba%b相比拟位运算,都是比拟费时的计算的。上面来看看jdk中是如何优化计算的:

static void getChars(int i, int index, char[] buf) {        int q, r;        int charPos = index;        char sign = 0;        if (i < 0) {            sign = '-';            i = -i;        }        // Generate two digits per iteration        while (i >= 65536) {            q = i / 100;        // really: r = i - (q * 100);            r = i - ((q << 6) + (q << 5) + (q << 2));            i = q;            buf [--charPos] = DigitOnes[r];            buf [--charPos] = DigitTens[r];        }        // Fall thru to fast mode for smaller numbers        // assert(i <= 65536, i);        for (;;) {            q = (i * 52429) >>> (16+3);            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...            buf [--charPos] = digits [r];            i = q;            if (i == 0) break;        }        if (sign != 0) {            buf [--charPos] = sign;        }    }

其中有一行代码:

q = (i * 52429) >>> (16+3);

下面这行公式约等于 q * 0.1,也就是说应用乘法计算比应用除法高效。

思路是这样:

当 i >= 65536时,是每两位取出数字,i /= 100,例如 i = 567235474,
(1)先取最初两位 7 和 4 放入buf数组中,i = 5672354,buf = { , , , , , , , '7', '4'};
(2)再取最初两位 5 和 4 放入buf数组中,i = 56723,buf = { , , , , , '5', '4', '7', '4'};
当 i < 65536 时,跳出循环,采纳每一次取出一位数字,也就是 i /= 10
(3)取最初一位 3 放入buf数组中,i = 5672,buf = { , , , , '3', '5', '4', '7', '4'};
(4)取最初一位 2 放入buf数组中,i = 567,buf = { , , , '2', '3', '5', '4', '7', '4'};
(5)取最初一位 7 放入buf数组中,i = 56,buf = { , , '7', '2', '3', '5', '4', '7', '4'};
(6)取最初一位 6 放入buf数组中,i = 5,buf = { , '6', '7', '2', '3', '5', '4', '7', '4'};
(7)取最初一位 5 放入buf数组中,i = 0,buf = { '5', '6', '7', '2', '3', '5', '4', '7', '4'},完结。

总结

对于Integer类临时介绍到这里,无关其它的包装类Long等源码局部也是相似的,后续就不再介绍,有趣味的小伙伴能够去钻研一下。