之前项目需要使用到进制转换,然后找到了Integer类提供的方法toString(int i, int radix),查看使用时顺便看了下源码。发现源码有的地方写的很巧妙。现在趁有空记录一下
先看一下源码:
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* 如果是10进制,直接转字符串即可 */
if (radix == 10) {
return toString(i);
}
// 存放转换进制后的字符数组
char buf[] = new char[33];
boolean negative = (i < 0);
// 将指针指向buf数组最后一位,以便后边存放字符
int charPos = 32;
if (!negative) {
i = -i;
}
/* 使用短除法来转换进制 */
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
其实上边使用的短除法,基本大家在数学都学过,如果忘了可以网上搜一下。
if (!negative) {
i = -i;
}
但是在这里为何把正数转为负数,再进行进制转换呢。网上查了一下别人的回答,使用正数也能得到相同的结果。难道这是多此一举?后来经过思考,其实并不是的。先来推导一下过程,假如将18转成2进制,即i=18,radix=2:
(1)将转为负数: i = -18;
(2)反复使用短除法:
buf : ...............0 , i : -9
buf : .............10 , i : -4
buf : ...........010 , i : -2
buf : .........0010 , i : -1
buf : .......10010
(3)如果negative为true,那么进制数前还要加个‘-’。
这里结果为10010。
假设我们按正数的方法进行,获得结果是相同的。如此看来,为何还要先转负数再转换呢,其实我们少考虑一种情况,边界值。int的范围是-2^31——2^31-1。当值为-2^31时,如果将其转为正数再进行进制转换,那么变为2^31已超出int的范围,其实java执行结果还是-2^31,还是负数。那么在while循环的i <= radix条件则不成立,无法获得正确的结果。
为何i = -2^31时,执行i = -i,i仍等于-2^31。
-2^31的补码为 1000 0000 0000 0000 0000 0000 0000 0000,当将其转为正数时,对应补码理解就是-x=~x+1,即补码取反加1。那么获得结果还是 1000 0000 0000 0000 0000 0000 0000 0000。
个人的理解大概是这样,欢迎大家来看,有什么不对地方请指点出来。突然感觉基础还是挺重要的,不知不觉就用到了大学学的计算机原理。