源碼
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
// BEGIN Android-changed: Cache the String for small values.
// int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
// 注意這裏的BEGIN Android-changed和 END Android-changed 註釋
// 在AndroidStudio中讀源碼有這一段
// 在Intellij中讀到的源碼是沒有BEGIN和END之間的這一段代碼的,
// 個人理解,不太恰當的比喻下就是android的jre和傳統Java開發的jre不一樣。
// 這個方法在不同運行環境下的真正實現不一樣
boolean negative = i < 0;
boolean small = negative ? i > -100 : i < 100;
// 判斷值在區間(-100,100),採用類似緩存機制的方式來讀取
if (small) {
// SMALL_NEG_VALUES 和 SMALL_NONNEG_VALUES 分別是(-100,0)和 [0,100)兩個區間正數對應字符串的緩存池
// 以私有靜態常量數組的形式被聲明在Integer中,隨着Integer的初始化而初始化,初始情況下爲空,長度爲100
final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES;
if (negative) {
// 在值爲負數的情況下,將其視作正數來進行處理
i = -i;
// 在smallValues數組中直接根據 i 作爲索引查詢字符串
if (smallValues[i] == null) {
// DigitOnes和DigitTens 是兩個靜態常量數組,值已經寫入好了,長度爲100
// 內容是位於區間 [0,99]的100個數,按照從0到99的順序,分別對應的個位數的字符和十位數的字符
smallValues[i] =
// 如果小於10,直接賦值smallValues[i] ‘-’+(查詢得到的個位數對應字符)
i < 10 ? new String(new char[]{'-', DigitOnes[i]})
// 否則賦值smallValues[i] ‘-’+(十位數字符+個位數字符)
: new String(new char[]{'-', DigitTens[i], DigitOnes[i]});
// 如果僅採用三元表達式 末尾 十+個 的方式,會給小於10的數字符補上0,所以不對
}
} else {
// 大概原理同上
if (smallValues[i] == null) {
smallValues[i] =
i < 10 ? new String(new char[]{DigitOnes[i]})
: new String(new char[]{DigitTens[i], DigitOnes[i]});
}
}
// 位於(-100,100)區間的數,經過上述代碼塊,已經在smallValue對應的緩存數組中生成或查詢到了值
// 直接按照索引返回即可
return smallValues[i];
}
// 對於位於(-∞,-100]和區間[100,∞)的數,先計算位數
int size = negative ? stringSize(-i) + 1 : stringSize(i);
// stringSize(i)方法用於計算數字的位數
//如果是負數還要留出一位符號位
// END Android-changed: Cache the String for small values.
char[] buf = new char[size]; // 生成對應位數的char數組
getChars(i, size, buf); // getChars(...)方法將每一位對應的char放入數組
// Android-changed: Use regular constructor instead of one which takes over "buf".
// return new String(buf, true);
return new String(buf); // 返回char數組組成的字符串
}
getChars(int i, int index, char[] buf)方法
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
// 負數全部當作正數處理
// 並單獨記錄符號爲sign
sign = '-';
i = -i;
}
// Generate two digits per iteration
// 當值大於65536時,每次循環,生成2位字符
// iEg=1165536,buf=[ , , , , , , ] charPos=7
while (i >= 65536) {
q = i / 100; // q記錄了下次循環時i 對應的初始數
// qEg=11655,則本次應該寫入‘3’,‘6’
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
// (q<<6)+(q<<5)+(q<<2)==q*2^6+q*2^5+q*2^2==q*(64+32+4)==q*100
// 採用左移的方式相比直接*100,在納秒級別可以看出,左移會明顯快很多。毫秒級別可能看不太清楚。
// r= i-(q*100) ==i-((i/100)*100)==i Mod(100) 既是該次應該寫入的兩位字符對應的值
// rEg=36
i = q;
buf [--charPos] = DigitOnes[r]; // 利用之前的DigitOnes和DigitTens
buf [--charPos] = DigitTens[r];
// bufEg=[ , , , , ,'3','6'] charPosEg=5,iEg=11655,下一輪會跳出循環
}
// iEg=11655
// 前面將 從第0位到第3位的數記錄到了buf中
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
// 2^19=524288
// q=( i* ((2^19+2)/10)) / 2^19 == i/10 ((2^19+2)/2^19 是int除int 在 jvm中計算結果爲1)
// 但是爲什麼要寫成 16+3?表示+3是精心選擇過的意義嗎?意義又在哪?
// 前面爲什麼又要選65536=2^16,選這幾個數的道理是什麼?沒搞懂。
// qEg=1165
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
// 同上 r=i-q*(2^3+2)
// rEg=11655-1165*10=5
buf [--charPos] = digits [r];
// digits[]是一個36位char數組,內容爲‘0’~‘9’,‘a’~'z'
// 在大於10進制的進制的toString中還會用到,所以有後面的'a'~'z'
// 此時buf=[ , , , ,5,3,6],charPosEg=4
i = q;
// iEg=1165,之後循環直到 i==0
if (i == 0) break;
}
if (sign != 0) {
// 如果存在符號'-',則在第一位放入符號
buf [--charPos] = sign;
}
}
stringSize方法,原理一看便知,不再贅述。
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}