在Integer源碼中有三個(gè)toString()方法
1、public String toString()
2、public static String toString(int i)
3、public static String toString(int i, int radix)
其中1繼承至object類,
完整代碼為:
public String toString() {
return toString(value);
}
在return會(huì)進(jìn)入第2個(gè)toString方法,源碼為
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
可以看到判斷
public static final int MIN_VALUE = 0x80000000;
if (i == Integer.MIN_VALUE)
return "-2147483648";
16進(jìn)制的MIN_VALUE換算成10進(jìn)制等于2147483648,可為什么當(dāng)i==2147483648時(shí),返回的字符串要加上負(fù)數(shù)呢?
這是因?yàn)镮nteger在計(jì)算機(jī)中用4個(gè)字節(jié)表示,每個(gè)字節(jié)8位,即:
00000000 00000000 00000000 00000000
其中正數(shù)范圍為1~2^31,因?yàn)榈谝晃挥脕肀硎菊?fù)符號(hào),所以只有31位
同理負(fù)數(shù)也為1~2^31,
那么會(huì)多出兩個(gè)碼
00000000 00000000 00000000 00000000
10000000 00000000 00000000 00000000
其中第一個(gè)表示為0,第二個(gè)表示為-2147483648(這跟原碼補(bǔ)碼反碼的知識(shí)有關(guān),這也是Integer取值范圍為-2^31 ~2^31-1的原因,負(fù)數(shù)比正數(shù)多一個(gè)值)
繼續(xù)源碼
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
其中stringsize源碼為:
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++)
if (x <= sizeTable[i])
return i+1;
}
它會(huì)返回參數(shù)x的位數(shù),比如20(2位)返回2,340(3位)返回3
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
那么size的意圖也很明顯了,如果負(fù)數(shù)先轉(zhuǎn)為正數(shù),求值后+1因?yàn)橐娣咆?fù)號(hào)"-"
接下來進(jìn)入getchar
int charPos = index;
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];
}
當(dāng)輸入的i大于65535時(shí)會(huì)先執(zhí)行這么一段方法,
舉例輸入為765432,則charPos=6(位數(shù)),q為7654,q << 6 則是把q放大2^6倍
((q << 6) + (q << 5) + (q << 2))即為放大q為64+32+4=100倍
則此時(shí)r=32,i等于7654
DigitOnes和DigitTens是兩個(gè)設(shè)計(jì)巧妙的數(shù)組
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',
} ;
它會(huì)把r的個(gè)位和十位取出來
此時(shí)buf 的值為:
[0,0,0,0,3,2]
接下來則繼續(xù)執(zhí)行
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;
}
其中2^19=524288, 52429/524288=0.1000003814697265
也就是q = i/10的意思,此時(shí)i為7654,則q為765
為什么不直接寫i/10而要拐外抹角寫這么復(fù)雜呢?這是因?yàn)槌撕臀灰频男试谟?jì)算機(jī)運(yùn)算中要比除高效,而為什么位移19位是因?yàn)?9是在Interger范圍內(nèi)精度最接近0.1的。
類似的可以看
2^18=262144, 26215/262144 =0.10000228881835938
2^19=524288, 52429/524288 =0.1000003814697265
2^20=262144, 104858/1048576=0.1000003814697265
繼續(xù)源碼,r則會(huì)取出個(gè)位上的數(shù),反復(fù)循環(huán)如此得到buf數(shù)組
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
最后調(diào)用return new String(buf, true),即完成了第二個(gè)toString方法
接下來我們看第三個(gè)toString方法
public static String toString(int i, int radix)
第三個(gè)toString支持進(jìn)制轉(zhuǎn)換,限制為MIN_RADIX=2,MAX_RADIX=36
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
MIN_RADIX=2很好理解,當(dāng)進(jìn)制為1時(shí)沒有意義,
MAX_RADIX為36則是因?yàn)閿?shù)字加上26個(gè)字母一共36個(gè),實(shí)際上可以用大寫字母繼續(xù)擴(kuò)充,這里理解為jdk只支持到36位
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'
};
當(dāng)radix為10時(shí),直接調(diào)用第二個(gè)toString方法
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
接下來源碼:
char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
我們可以知道Integer的2進(jìn)制一共4*8-1為31位,算上符號(hào)也只用32位,為什么new char[33]需要33位呢?這是因?yàn)槲覀兩厦嬲f的特殊補(bǔ)碼
10000000000000000000000000000000
它表示的是-2147483648,而2147483648占用了32位,加上符號(hào)一共就需要32位了。
if (!negative) {
i = -i;
}
這里將i統(tǒng)一轉(zhuǎn)換成負(fù)數(shù)處理,與第二個(gè)toString不同,第二個(gè)toString是統(tǒng)一轉(zhuǎn)換成正數(shù)處理。這里我認(rèn)為統(tǒng)一轉(zhuǎn)換成正數(shù)也可以,后續(xù)就是普通的進(jìn)制轉(zhuǎn)換算法。
至此,3個(gè)toString方法就全部說完了。