为什么在Java中对int进行递增最终会得到一个负数?

4

我试图检查不同的输入并在Java中创建无限循环,我发现一旦int超过最大限制,它会变成负数-2147482958。我只是在无限循环中增加int...

代码:

public static void infiniteLoop(){
        for(int i=0;i>-1;i++){
            i = i + 1000;
            System.out.println(i);
        }
    }

最后打印出来的值是,
2147483337
-2147482958

现在,为什么会变成负数呢?

4
如果你想被认真对待,你应该真正改变标题。 - Junuxx
@所有人,非常抱歉有点幽默。我知道这是一个严肃的地方,但我正在阅读关于停机问题的内容,由于找不到一种方法来检查是否能够检测出程序是否会在给定输入下停止运行,我感到非常沮丧 :) - TeaCupApp
@bmargulies,谢谢,再次抱歉! - TeaCupApp
4个回答

11
因为在Java中,当一个int类型的计算溢出时,这就是指定要发生的情况。 JLS 15.18.2 “如果整数加法溢出,则结果是以某个足够大的二进制补码格式表示的数学和的低位比特。如果溢出发生,则结果的符号与两个操作数值的数学和的符号不同。”
(这并没有明确说明溢出总是会得到负数。事实并非总是如此。但如果你遵循这个规则,它可以解释为什么将Integer.MAX_VALUE增加+1会得到Integer.MIN_VALUE...)

+1,很有趣,谢谢让我查看文档!我之前应该做过了。谢谢。 - TeaCupApp
令人惊讶的是它没有引发异常。 - theglauber
4
@theglauber说:“我不确定这是否令人惊讶。要抛出异常,就意味着每个算术操作都必须伴随额外的周期来检查溢出。”需要翻译成通俗易懂的中文。 - Oliver Charlesworth
1
一些库具有检查算术溢出的方法,特别是Guava的IntMath和Apache的ArithmeticUtils - Louis Wasserman
@OliCharlesworth - 是的,这就是为什么。但感觉有点不像Java风格。例如,C语言出于同样的原因不会检查数组访问是否越界,但Java会。这只是编程语言总是一系列妥协的提醒。 - theglauber
1
@theglauber - 整数溢出和数组越界的区别在于后者可能会践踏内存并导致JVM崩溃,如果不被捕获。如果存在未检测到的内存践踏,则无法安全地执行(重定位)GC。 - Stephen C

5
根据文档:
int 数据类型是一个32位有符号的二进制补码整数。它的最小值为-2,147,483,648(0x80000000),最大值为2,147,483,647(0x7FFFFFFF)(包括)。
所以,当你给一个整数的最大值加1时:
0x7FFFFFFF + 0x00000001 = 0x80000000(-2,147,483,648)

4

1

因为int的范围是从-2,147,483,648到2,147,483,647。因此,一旦它达到上限,它就会溢出并从负数开始。

请参见文档:

int数据类型是32位带符号的二进制补码整数。它的最小值为-2,147,483,648,最大值为2,147,483,647(包括边界)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接