Integer源码

2019-07-17  本文已影响0人  xiaolyuh

总览

微信截图_20180418144219.png

Integer是int类型的包装类,继承自Number抽象类,实现了Comparable接口。提供了一些处理int类型的方法,比如int到String类型的转换方法或String类型到int类型的转换方法,当然也包含与其他类型之间的转换方法。

属性

private final int value;
@Native public static final int   MIN_VALUE = 0x80000000;
@Native public static final int   MAX_VALUE = 0x7fffffff;
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
@Native public static final int SIZE = 32;
public static final int BYTES = SIZE / Byte.SIZE;
final static char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' ,
        '6' , '7' , '8' , '9' , 'a' , 'b' ,
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    };
final static char [] DigitOnes = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        } ;
final static char [] DigitTens = {
        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
        } ;
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                      99999999, 999999999, Integer.MAX_VALUE };

方法分析

toString

将int转成字符串

public static String toString(int i) {
    // 先判断i是不是最小值,如果是就直接返回
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    // 调用stringSize计算int值对应字符串的长度,负数有一个符号位所以要加一
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    // 新建一个临时数组,存放int值的每一位转成char后的值
    char[] buf = new char[size];
    // 将int值的每一位转成char后放到buf中
    getChars(i, size, buf);
    // 返回一个字符串
    return new String(buf, true);
}

stringSize

获取一个int值对应字符串的长度。

// 利用sizeTable属性,通过该方法可以高效的去获取一个int值对应字符串的长度,而不必进行除法或者取模运算
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

getChars

在toString方法中调用,主要所用是,将int值的每一位转成char后放到buf中。

static void getChars(int i, int index, char[] buf) {
    int q, r;
    // buf数组的长度
    int charPos = index;
    // 符号标示位
    char sign = 0;
    // 如果i是负数,那么将符号位设为“-”,并且取i的相反数。
    if (i < 0) {
        sign = '-';
        i = -i;
    }

    // Generate two digits per iteration
    //③如果i大于63336,两个字节的长度,那么久每次取1的后两位出来处理
    while (i >= 65536) {
        // 去掉i的后两位后并将值赋值给q,如果i=65537,那么现在q=655
        q = i / 100;
        // really: r = i - (q * 100);
        // ①计算后两位数字,如果i=65537,那么r=37,计算公式就是【 r = i - (q * 100)】
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        // 通过DigitOnes和DigitTens获取r的个位和十位对应的char。
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i <= 65536, i);
    for (;;) {
        // ②就是q = i/10,如果i=655,那么q=65
        q = (i * 52429) >>> (16+3);
        // 取i的最后一位,就是r=i-(q*10),r=5
        r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
        // 通过digits数组获取对应的char
        buf [--charPos] = digits [r];
        // q=65,并赋值给i,进入下一个循环
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}

说明:

2^10=1024, 103/1024=0.1005859375
2^11=2048, 205/2048=0.10009765625
2^12=4096, 410/4096=0.10009765625
2^13=8192, 820/8192=0.10009765625
2^14=16384, 1639/16384=0.10003662109375
2^15=32768, 3277/32768=0.100006103515625
2^16=65536, 6554/65536=0.100006103515625
2^17=131072, 13108/131072=0.100006103515625
2^18=262144, 26215/262144=0.10000228881835938
2^19=524288, 52429/524288=0.10000038146972656
选19是在不超出整形范围内,精度最高的。

不知道有没有人发现,其实65536* 52429是超过了int的最大值的,一旦超过就要溢出,那么为什么还能保证(i * 52429)>>> 19能得到正确的结果呢? 这和>>>有关,因为>>>表示无符号右移,他会在忽略符号位,空位都以0补齐。一个有符号的整数能表示的范围是 -2147483648至2147483647,但是无符号的整数能表示的范围就是 0-4,294,967,296(2^32),所以,只要保证i * 52429的值不超过2^32 次方就可以了。65536是2^16 ,52429正好小于2^16,所以,他们的乘积在无符号向右移位就能保证数字的准确性。

上一篇下一篇

猜你喜欢

热点阅读