JDK源碼解讀(第六彈:Integer之toUnsignedString0)

再來看一下還有幾個跟toString差不多的方法,分別是toHexString,toOctalString,toBinaryString,顧名思義,就是轉成十六進制/八進制/二進制形式的字符串,源碼如下:

    public static String toHexString(int i) {
        return toUnsignedString0(i, 4);
    }

    public static String toOctalString(int i) {
        return toUnsignedString0(i, 3);
    }

    public static String toBinaryString(int i) {
        return toUnsignedString0(i, 1);
    }

可以看到這三個方法其實都是以不同的參數調用了toUnsignedString0這個方法,那我們就來仔細地分析一下這個方法:

    private static String toUnsignedString0(int val, int shift) {
        // assert shift > 0 && shift <=5 : "Illegal shift value";
        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
        char[] buf = new char[chars];

        formatUnsignedInt(val, shift, buf, 0, chars);

        // Use special constructor which takes over "buf".
        return new String(buf, true);
    }

     static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
        int charPos = len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[offset + --charPos] = Integer.digits[val & mask];
            val >>>= shift;
        } while (val != 0 && charPos > 0);

        return charPos;
    }

toUnsignedString0方法是先計算轉換成對應進制需要的字符數,也就是得到chars,然後再通過 formatUnsignedInt 方法來填充字符數組得到結果。最複雜的就在於這個 formatUnsignedInt 方法。
在 formatUnsignedInt 方法中,

        int radix = 1 << shift;
        int mask = radix - 1;

這兩行的作用是要得到對應進制數的掩碼。什麼意思呢?
如果是二進制,因爲2的1次方是2,所以shift就是1,那麼radix就是1左移1位得到2,mask就是1,對應的二進制就是1;
如果是八進制,因爲2的3次方是8,所以shift就是3,那麼radix就是1左移3位得到8,mask就是7,對應的二進制就是111;
如果是十六進制,因爲2的4次方是16,所以shift就是4,那麼radix就是1左移4位得到16,mask就是15,對應的二進制就是1111;

接下來的循環中重點是理解val & mask
之前我們在分析toString時講到,十進制轉換成其他進制是怎麼轉的,是通過不斷地除以進制數最後把餘數拼接。如果是轉換成八進制或十六進制這種進制數爲2的整數次方的進制,其實有更快的算法,就是先得到二進制,然後每幾位一組轉換。

比如要把19轉換成八進制:

  1. 先把19轉成二進制,也就是10011;
  2. 因爲8是2的3次方,所以把10011從低位開始每3位一組劃分,也就是10 011;
  3. 把10 011按每一組轉爲八進制,也就是2 3,所以19的八進制表示就是23。

循環val & mask的過程就像分組轉換的過程,每次循環可以將mask對應的位數得到,再利用digits數組轉換成對應的字符,這個字符就是這次分組的這幾位所對應的結果,每次分組得到結果以後把val右移相應的位數,繼續下一輪的循環分組。
還是以19轉成八進制舉例,看一下程序是怎麼走的:
val爲19,shift爲3,radix爲8,mask爲7。
第一次循環:19 & 7就是10011 & 111,結果爲11,也就是3,通過digits數組得到這一位字符爲3。然後10011右移3位,得到val爲10。
第二次循環:10 & 111,結果爲10,也就是2,通過digits數組得到這一位字符爲2。然後10右移3位,得到val爲0,循環結束。
最終結果就是23。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章