再來看一下還有幾個跟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轉換成八進制:
- 先把19轉成二進制,也就是10011;
- 因爲8是2的3次方,所以把10011從低位開始每3位一組劃分,也就是10 011;
- 把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。