19

在 java String source code中,很少有地方用以下注释注明:

// Note: offset or count might be near -1>>>1.

考虑以下示例:

public String(char value[], int offset, int count) {
    if (offset < 0) {
        throw new StringIndexOutOfBoundsException(offset);
    }
    if (count < 0) {
        throw new StringIndexOutOfBoundsException(count);
    }
    // Note: offset or count might be near -1>>>1.
    if (offset > value.length - count) {
        throw new StringIndexOutOfBoundsException(offset + count);
    }
    this.offset = 0;
    this.count = count;
    this.value = Arrays.copyOfRange(value, offset, offset+count);
}

正如我们所见,offsetvalue.length都是countint因此该值可能是 -1、0、1 或任何其他整数。评论中的“近”和“>>>”是什么意思,我在这里遗漏了什么吗?

4

2 回答 2

21

该值-1>>>1 == 2147483647int您在 Java 中可以拥有的最大值。

换句话说,-1>>>1 == Integer.MAX_VALUE. 当您使用接近此类限制的值进行数学运算时,您获得意外结果的机会就会增加。例如,由于整数溢出int a = (-1>>>1); System.out.println(a < a + 1);而打印,尽管人们可以期望该代码总是打印,因为在纯数学中,对于任何整数来说.falsetruenn < n + 1

那段代码的作者只是在解释他(明智的)决定写

if (offset > value.length - count)

而不是看起来相似但不等价的

if (offset + count > value.length)

最后一个版本可能会导致整数溢出,这对后面的代码来说可能是一个巨大的麻烦。他警告说,至少有一个offsetcount可能是接近 的值Integer.MAX_VALUE,这增加了溢出的可能性。

对于第一个版本(您提到的 String 的源代码中使用的版本),永远不会发生溢出:您肯定知道offsetcount都是正数或 0 因为先前的检查,并且value.length也是正数或 0 因为长度在 Java 中,数组的值总是正数或 0,因此不会发生溢出问题!

除了记录选择之外,作者还警告其他开发人员(包括他未来的自己),以这种方式编写该行有一个非常具体的原因,以避免任何人试图将其替换为(可能更自然寻找)第二,引入错误的错误版本。

于 2013-04-17T07:50:21.300 回答
5

您可能想查看按位和位移运算符以了解有关>>>运算符的说明:

无符号右移运算符“>>>”将零移到最左边的位置

假设你有:

int a = -1;
a = a >>> 1;
System.out.println(a);

然后a将是 2147483647 (即Integer.MAX_VALUE

为什么?

由于 >>>运算符填充零并且无论正数和负数都只填充零。因此,例如,如果您有:

12 >>> 2

(00000000 00000000 00000000 000011 00 >>> 2) 那么结果是 3。

(即 00000000 00000000 00000000 00000011)。

所以,如果你这样做:

System.out.println(Integer.toBinaryString(-1>>>1));

这将打印:

1111111111111111111111111111111

当然,将其转换为十进制,这是 2147483647。

正如@BrunoReis (+1) 在他的回答中解释的那样,这样做的原因是为了防止可能的整数溢出问题。

于 2013-04-17T07:44:44.423 回答