Java Study--Interger.toString(int i)(10進制數版本)

源碼

 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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章