System.out.println(Integer.MAX_VALUE + 1 == Integer.MIN_VALUE);
是真的。
我知道Java中的整数是32位且不能超过2 31 -1,但我无法理解为什么在MAX_VALUE
中添加1导致{{ 1}}而不是某种例外。没有提到透明转换为更大类型的东西,比如Ruby。
是否在某处指定了此行为?我能依靠吗?
答案 0 :(得分:28)
因为整数溢出。当它溢出时,下一个值为Integer.MIN_VALUE
。 Relevant JLS
如果整数加法溢出,则结果是数学和的低阶位,如某些足够大的二进制补码格式所示。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。
答案 1 :(得分:24)
整数存储空间溢出且that is not indicated in any way, as stated in JSL 3rd Ed.:
内置整数运算符不以任何方式指示溢出或下溢。如果需要空引用的转箱(§5.1.8),则整数运算符可以抛出
NullPointerException
。除此之外,唯一可以抛出异常(§11)的整数运算符是整数除运算符/
(§15.17.2)和整数余数运算符%
(§15.17.3),其中如果右侧操作数为零,则抛出ArithmeticException
;增量和减量运算符++
(§15.15.1,§15.15.2)和--
({{3 }},§15.14.3),如果需要装箱转换§15.14.2并且没有足够的内存可用于执行转换,则可以抛出OutOfMemoryError
。
4位存储中的示例:
MAX_INT: 0111 (7)
MIN_INT: 1000 (-8)
MAX_INT + 1:
0111+
0001
----
1000
答案 2 :(得分:8)
您必须了解整数值如何以二进制形式表示,以及二进制加法的工作原理。 Java使用称为二进制补码的表示,其中数字的第一位表示其符号。每当你向最大的java Integer(其位符号为0)加1时,它的位符号变为1,数字变为负数。
此链接详细说明了http://www.cs.grinnell.edu/~rebelsky/Espresso/Readings/binary.html#integers-in-java
-
Java语言规范在此处理此行为:http://docs.oracle.com/javase/specs/jls/se6/html/expressions.html#15.18.2
如果整数加法溢出,则结果是数学和的低阶位,如某些足够大的二进制补码格式所示。如果发生溢出,则结果的符号与两个操作数值的数学和的符号不同。
这意味着您可以依赖此行为。
答案 3 :(得分:7)
在大多数处理器上,算术指令无溢出故障模式。他们设置了一个必须检查的标志。这是一个额外的指令,所以可能更慢。为了使语言实现尽可能快,通常会指定语言来忽略错误并继续。对于Java,行为在JLS中指定。对于C,语言不指定行为,但现代处理器将表现为Java。
我相信有些(笨拙的)Java SE 8库提出了溢出和无符号操作的建议。我相信在DSP领域很受欢迎的行为是将值限制在最大值,因此Integer.MAX_VALUE + 1 == Integer.MAX_VALUE
[不是Java]。
我确信未来的语言将使用任意精度的int,但暂时还没有。需要更昂贵的编译器设计才能快速运行。
答案 4 :(得分:4)
当您跨越国际日期行时日期发生变化的原因相同:那里存在不连续性。它内置于二元加法的本质中。
答案 5 :(得分:4)
这是一个众所周知的问题,即整数在二进制层表示为two's complement。当您将2的补码数的最大值加1时,您将获得最小值。老实说,所有整数在java存在之前都是这样的,并且改变Java语言的这种行为会给整数数学带来更多的开销,并且混淆了来自其他语言的程序员。
答案 6 :(得分:3)
将3
(二进制11
)添加到1(二进制1
)时,您必须更改为0
(二进制0
)所有二进制1
从右边开始,直到你得到0,你应该更改为1
。 Integer.MAX_VALUE
所有地方都填充了1
,因此仅保留0
个。
答案 7 :(得分:0)
byte a=127;//max value for byte
byte b=1;
byte c=(byte) (a+b);//assigns -128
System.out.println(c);//prints -128
这里我们强制加法并将其转换为字节。 那么将会发生的情况是,当我们达到 127(一个字节的最大可能值)并加上 1 时,该值从 127 翻转(如图所示)并变为 -128。 值开始在类型周围盘旋。
整数也是如此。
还有 integer + integer 保持整数(不像 byte + byte 被转换为 int [除非像上面那样强制转换])。
int int1=Integer.MAX_VALUE+1;
System.out.println(int1); //prints -2147483648
System.out.println(Integer.MIN_VALUE); //prints -2147483648
//below prints 128 as converted to int as not forced with casting
System.out.println(Byte.MAX_VALUE+1);
答案 8 :(得分:-1)
导致溢出,并且两个兼容的自然计数在“第二个循环”上进行,我们位于最右边的位置2147483647,求和1之后,我们出现在最左边的位置-2147483648,接下来的增量是-2147483647,-2147483646, -2147483645,...如此反复,直到最右边,在此位深度上求和器的性质。
一些例子:
int a = 2147483647;
System.out.println(a);
给出:2147483647
System.out.println(a+1);
给出:-2147483648(由于溢出和两个兼容的自然计数在“第二循环”中进行,我们位于最右边的位置2147483647,求和1之后,我们出现在最左边的位置-2147483648,下一次增加是- 2147483648,-2147483647,-2147483646 ...等等,然后又一次又一次地前进到最右端,在这个位深度上求和器的性质)
System.out.println(2-a);
gives:-2147483645(-2147483647 + 2似乎是数学逻辑)
System.out.println(-2-a);
给出:2147483647(-2147483647-1-> -2147483648,-2147483648-1-> 2147483647前面的答案中描述的某些循环)
System.out.println(2*a);
给出:-2(2147483647 + 2147483647-> -2147483648 + 2147483646再次是数学逻辑)
System.out.println(4*a);
给出:-4(2147483647 + 2147483647 + 2147483647 + 2147483647-> -2147483648 + 2147483646 + 2147483647 + 2147483647-> -2-2(根据最后一个答案)-> -4)`