1 /** 2 * All possible chars for representing a number as a String 3 */ 4 final static char[] digits = { 5 '0' , '1' , '2' , '3' , '4' , '5' , 6 '6' , '7' , '8' , '9' , 'a' , 'b' , 7 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 8 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 9 'o' , 'p' , 'q' , 'r' , 's' , 't' , 10 'u' , 'v' , 'w' , 'x' , 'y' , 'z' 11 }; 12 13 /** 14 * Convert the integer to an unsigned number. 15 */ 16 private static String toUnsignedString(int i, int shift) { 17 char[] buf = new char[32];//当shift为1二进制时,char数组大小32刚好,而当shift为3,4时,数组大小有余 18 int charPos = 32;//当数组有余时,便于取char数组中的数据 19 int radix = 1 << shift;//算数左移,radix中间变量用于计算mask 20 int mask = radix - 1;//mask掩码用于获取i的shift位低位,mask二进制数每一位都是1 21 do { 22 buf[--charPos] = digits[i & mask];//取出i二进制数低位shift位,将对应的字符存入buf //新建数组大小时[]填32,但是在数组赋值时[]填0~31 23 i >>>= shift;//逻辑右移,剔除已取出的shfit位低位 24 } while (i != 0); 25 26 return new String(buf, charPos, (32 - charPos)); 27 }
1. 掩码mask的计算。shift参数用于区分不同进制,比如二进制的shift=1,mask=1;八进制的shift=3,mask=7;十六进制的shift=4,mask=15。
2. 右移使用的是>>>而不是>>。位运算中的右移分为算术右移(>>)和逻辑右移(>>>)。在进行算术右移时,最高位补符号位;而在进行逻辑右移时,最高位补0。如果这里使用的算术右移,那么对于像-1这样的负数,不论进行多少次右移操作都不可能变成0,所以会造成死循环。
3. 使用的是do-while而不是while。这是一个极其重要的细节,如果使用的是while,那么对于i=0的场景则会返回空字符串。
4. 算术左移(<<)、右移(>>)主要用来进行有符号数的倍增、减半;
逻辑左移(<<<)、右移(>>>)主要用来进行无符号数的倍增、减半。(左移都是低位补0,算数右移高位补符号位,逻辑右移高位补0)
5.
二进制:
public static String toBinaryString(int i) {
return toUnsignedString(i, 1);
}
八进制:
public static String toOctalString(int i) {
return toUnsignedString(i, 3);
}
十六进制:
public static String toHexString(int i) {
return toUnsignedString(i, 4);
}
补充:每个IP地址都由网络号和主机号两部分组成,通过子网掩码(subnet mask)区分网络号和主机号(子网掩码:255.0.0.0;255二进制数1111)