Java內置了API: Integer.toBinaryString();
先看源碼是怎么寫的
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);
}
核心是兩部分
一計算mag,mag指的是二進制需要占用的位數, eg: 10 => 1010 需要四位。
另一個就是formatUnsignedInt(); 去轉換,等下去具體看。
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
}
這個方法里都是左移右移的位運算,左移就是末尾加0 即乘以2,eg: 10 <<= 1 即 10100 等於20。右移是反過來 10 >>= 1 即 101 等於5。
所以這幾個if是在干嘛呢,舉個例子理解,以10為例,我們知道它的二進制是四位,不夠十六位,所以再過了第一個if之后會變成1010...(16),其他幾個類似,你可以在腦子里過一遍。首先我們確定i最大是31位,而規律就是過完這些if,i 要么是32位要么是31位,那么它再右移31位 結果要么是0要么是1。而n就記錄了這個過程中實際補了多少位。我只能分析出這個規律,不能想出如何想到的這樣的想法來計算。我們的例子10 對應結果 n = 28; mag = 4; 可以腦補下它執行了哪幾個if。
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;
}
這是第二部分真正去轉換的部分,猛一看不懂這些變量radix mask代表什么意思,但是我們通過debug將值帶入進去發現mask = 1。然后得到轉換值的關鍵在於digits[val & mask], digits是定義的一個數組存放了[0-9][a-z]。然后 奇數&1 = 1; 偶數 & 1 = 0; 為什么會這樣,還是以10為例 1010 & 0001 只比較最后一位即可 因為任何數 & 0都為0,所以 0 & 1 = 0;實際上digits[0] = 0; digits[1] = 1; 我們可以找到這個方法的核心將最后一位 & 1 然后右移移除最后一位。
我最后再想一下平時的寫法
public static String int2Binary(int n) {
StringBuilder result = new StringBuilder();
while (n > 0) {
if (n % 2 == 0) {
result.append("0");
} else {
result.append("1");
}
n = n / 2;
}
return result.reverse().toString();
}
唔 比內置的實現容易懂,當然效率上肯定會差一些。