JDK 源码 Integer解读之一(toString)

1:首先我们可以通过一个main函数,通过断点调试,正式开启Integer.toString()方法之旅。
public static void main ( String[] arg ) {

System.out.println( Integer.toString( 65537 ) );

}
2: 首先我们会看到进入toString(int i)的方法之内
public static String toString(int i) {

if (i == Integer.MIN_VALUE) (1)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); (2)
    char[] buf = new char[size]; (3)
    getChars(i, size, buf); (4)
    return new String(buf, true); (5)
}

从(1)中我们就可以看到 判断是否为整数的最小的数,是的话,直接返回"-2147483648"字符串,在(2)中这里通过 stringSize(-i) 判断是否为小数 二进制中,小数的第一位是符号位,负数等于所比正数多了一位,在(3)中新创建了一个char[]数组,我们通过研究string的源码可知,String的本质就是一个char[]数组,对String的操作,就是操作char[]里面的每一个对象,为了搞清楚(4)与(5)的作用,首先,我们先进入stringSize(i)的方法里面都看看做了什么。

3: 高效的位数计算方法 stringSize(i);

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,

99999999, 999999999, Integer.MAX_VALUE };
static int stringSize(int x) {
    for (int i=0; ; i++) (1)
        if (x <= sizeTable[i]) (2)
            return i+1;
}

从(1)中可知,首先进入一个无限for循环中,但是由于sizeTable参数的限制,其实最多可以循环10此,例如我们,断点调试时传入的值是65537,那么它就会循环5次,得到是一个5位的数字,那么就返回4。char[] buf = new char[4],
正好就可以创建一个正好放下65537的数组。

4: 功能强大的getChars(i, size, buf);

static void getChars(int i, int index, char[] buf) {

int q, r;
    int charPos = index;
    char sign = 0;
    if (i < 0) {      (1)
        sign = '-';
        i = -i;
    }
    while (i >= 65536) {  (2)
        q = i / 100;
        r = i - ((q << 6) + (q << 5) + (q << 2)); (3)
        i = q;
        buf [--charPos] = DigitOnes[r];  (4)
        buf [--charPos] = DigitTens[r];  (5)
    }
    for (;;) { (6)
        q = (i * 52429) >>> (16+3);  (7)
        r = i - ((q << 3) + (q << 1));  (8)
        buf [--charPos] = digits [r];  (9)
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;  (10)
    }
}

从(1)处可知,我们知道负数的第一位是“-”号,并且负数比正数多了一位,除了“-”号位之外,所有的内容和正数完全相同,紧接着,会进入(2)的一个循环语句,为什么是65536呢,我们知道65536正好等于2的16次方,二正数的最大值是2的32次方减1,可以说,65536是正数的最大值的一半,大于65536的位高位数,小于65536的是低位数,65537/100正好是655,((q << 6) + (q << 5) + (q << 2))这一段的作用等于 (q * 100),通过位运算与加法运算,避免乘除运算以提高效率。紧接着r=37进入(4)和(5)的数组,(4)和(5)的数组设计简直称为神奇。
 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 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',
    } ;
    
通过这两个数组,正好得到buf [4]=7,buf [3]=3的值。接下来,就会进入(6)为代表的for无限循环中(其实有限的,这样写感觉好精炼),(7)的作用相当于除以10,右移16+3也就是右移19位,也就是除以2的19次方,2的19次方=524288 ,而52429除以524288为0.1000003814697266的精度已经很多了,就几乎等于0.1,而52429/524288得到的数字精度在不超出整形范围内,精度是最高的。(8)r = i - ((q << 3) + (q << 1))相当于r = i-(q*10),也是为了提高运算效率。类似的通过(9)与(10)即可得到字符数组 char[] ={"6","5","5","3","7"}

至此,最后调用new String(buf, true)方法,返回想要的字符串

相关推荐