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)方法,返回想要的字符串