12

看了java 1.7.0_09版本的源码,发现Integer类的toString方法的实现使用负int来计算mod运算,有什么意义吗?代码如下:

public static String toString(int i, int radix) {

    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        radix = 10;

    /* Use the faster version */
    if (radix == 10) {
        return toString(i);
    }

    char buf[] = new char[33];
    boolean negative = (i < 0);
    int charPos = 32;

    if (!negative) {     
        i = -i;                //***** change i to negative
    }

    while (i <= -radix) {
        buf[charPos--] = digits[-(i % radix)];   //***** change back to positive after 
                                                 //***** mod operation
        i = i / radix;
    }
    buf[charPos] = digits[-i];

    if (negative) {
        buf[--charPos] = '-';
    }

    return new String(buf, charPos, (33 - charPos));
}
4

1 回答 1

13

根据该算法,您需要一个小的 ( < radix) 非负整数流,它将用从右到左的数字填充字符缓冲区。进行这项工作的标准小学方法是在数字的开头放一个符号,然后打印数字的绝对值。

但是想象一下,如果规则i在那个循环中总是积极的:

if (negative) {
    i = -i; // change i to positive
}

如果i恰好是Integer.MIN_VALUE,那么-i也恰好是Integer.MIN_VALUE二进制补码整数变量可以存储的负整数比它们存储的正整数多一个。但是,如果不变量i始终是绝对值,则它将始终适合int.

为什么不直接使用Math.abs()if阻止?自然地,整数在许多计算机程序中被非常频繁地转换为字符串,因此toString尽可能快地保持是很有用的。问题是,当编译为机器代码时,Math.abs()if语句都可能被编译为使用分支指令。分支往往会干扰指令流水线;因此,在关注性能时,您可能会选择if尽可能从循环中删除语句。

注意:这种优化很少是一个好主意!除非您的代码被非常频繁地调用(例如此代码),或者您正在构建一个拥有大量用户和很少读者/修改器的库(例如此代码),否则性能提升是微乎其微的,并且它使代码更难阅读、理解和改变。通过进行这种优化,Java 工程师可能会稍微加快您的代码速度——但如果您将这样的技术应用到您编写的代码中,您的同事/评分者可能不会倾向于询问 Stack Overflow 为什么您的代码如此难以理解。:)

TL;DR:只是一个有根据的猜测,但这是二进制补码数学和代码优化的组合。

于 2012-10-26T05:08:06.470 回答