对于java源码Interger类toBinaryString的理解
对于java源码Interger类toBinaryString的理解
目录
源码
toBinaryString
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);
}
numberOfLeadingZeros
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;
}
formatUnsignedInt
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;
}
toBinaryString
对于toBinaryString,返回参数数值的补码形式,正数则忽略前面的0。(官方注释:返回表示传入参数的一个无符号(这里无符号大概只是指前面没有+-号,但还是有符号位) 的二进制字符串。如果参数为负数x,返回值为 2^32 + x 【就是它的补码】)
toUnsignedString0概述
可以看出,该方法传入了 val 和 shift 两个参数,这两个参数分别代表了数值和进制。对于shift,1代表2进制,3代表8进制,4代表16进制。
代表主要功能是代码的主要流程是分为两步: 第一步,计算出用于表示二/八/十六进制的字符数组的长度保存在mag参数内;第二步,使用formatUnsignedInt方法填充字符数组,得到所需进制表示的字符串并返回。
numberOfLeadingZeros
第一步中字符数组长度的计算是通过numberOfLeadingZeros方法计算int变量的计算机二进制表示的高位连续0位的数量,进而获得最高非0位到最低位的长度,也就是需要表示的位数。
以整数6为例,其在计算机中的二进制存储为 0000 0000 0000 0000 | 0000 0000 0000 0110
步骤如下 首先i=6≠0。
首个if的判断,如果无符号右移16位,即0000 0000 0000 0000 | 0000 0000 0000 0000,可知符合条件,则n=1+16=17,i左移16位得 0000 0000 0000 0110 | 0000 0000 0000 0000 |
进入下一个if,如果无符号右移24位,即0000 0000 0000 0000 | 0000 0000 0000 0000,可知符合条件,则n=17+8=25,i左移8位得 0000 0110 0000 0000 | 0000 0000 0000 0000 |
进入下一个if,如果无符号右移28位,即0000 0000 0000 0000 | 0000 0000 0000 0000,可知符合条件,则n=25+4=29,i左移4位得 0110 0000 0000 0000 | 0000 0000 0000 0000 |
进入下一个if,如果无符号右移30位,即0000 0000 0000 0000 | 0000 0000 0000 0001,不符合条件 |
执行 n = n-i »> 31,得到n=29,mag = 32 -29 = 3,即得出最高非零位前面的0的个数。继续计算得chars = 3,故创建一个字符数组buf,长度为3。
formatUnsignedInt
val = 6, shift = 1, buf = new char[3], offset = 0, len = 3
charPos = 3表示有效位的个数,radix = 2表示要转换成二进制的基数,若是要转换后八进制,则radix=8,同理,十六进制radix=16;mask = 1,一般我们要将十进制转换成其他进制的话,只需要&(与)上对应的进制基数即可得到结果,就好比是八进制的话就&7、十六进制的话就&15,这是最快得到十六进制表示的数值。
例如要把19转换成八进制:
1.先把19转成二进制,也就是10011;
2.因为8是2的3次方,所以把10011从低位开始每3位一组划分,也就是10 011;
3.把10 011按每一组转为八进制,也就是2 3,所以19的八进制表示就是23。(二进制同理,个人感觉八进制更好理解)
val为6,shift为1,radix为2,mask为1。
第一次循环:6 & 1就是0110 & 0001,结果为0,通过digits数组得到这一位字符
为0(注意,这一步已经转化为字符型)。然后0110右移1位,得到val为011。
第二次循环:011 & 001,结果为1,通过digits数组得到这一位字符
为1。然后011右移1位,得到val为01。
第二次循环:01 & 01,结果为1,通过digits数组得到这一位字符
为1。然后01右移1位,得到val为0,循环结束。
最终结果为110(二进制),储存在buf字符数组并输出
#附digits表
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};