为什么Integer.MAX_VALUE + 1 == Integer.MIN_VALUE?
System.out.println(Integer.MAX_VALUE + 1 == Integer.MIN_VALUE);
是真的。
我知道在Java中的整数是32位,不能超过2 ^ 31-1,但我不明白为什么加1到MAX_VALUE结果在MIN_VALUE而不是某种exception。 没有提到像透明转换到更大的types,就像Ruby一样。
这种行为指定的地方? 我可以依靠吗?
因为整数溢出。 当它溢出时,下一个值是Integer.MIN_VALUE
。 相关的JLS
如果整数加法溢出,那么结果是math和的低位,如用一些足够大的二进制补码格式表示的。 如果发生溢出,则结果的符号与两个操作数值的math和的符号不同。
整数存储溢出并且不以任何方式指示,如JSL第3版所述。 :
内置的整数运算符不会以任何方式指示上溢或下溢。 如果需要对空引用进行拆箱转换(第5.1.8节) ,则整型运算符可能会引发
NullPointerException
。 除此之外,可以抛出exception(§11)的唯一整数运算符是整数除法运算符/
(第15.17.2节)和整数余数运算符%
(第15.17.3节) ,如果右键点击时抛出ArithmeticException
,手操作数为零,递增和递减操作符++
( §15.15.1 , §15.15.2 )和--
( §15.14.3§§15.14.2 ),如果装箱转换可以抛出OutOfMemoryError
(§5.1 .7)是必需的,没有足够的内存可用于执行转换。
4位存储示例:
MAX_INT: 0111 (7) MIN_INT: 1000 (-8)
MAX_INT + 1:
0111+ 0001 ---- 1000
我相信这个链接解释你所看到的: http : //en.wikipedia.org/wiki/Two's_complement
您必须了解整型值如何以二进制forms表示,以及二进制加法如何工作。 Java使用称为二进制补码的表示法,其中数字的第一位表示其符号。 无论何时将1添加到最大的具有位符号0的Java Integer,其位标记都将变为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
如果整数加法溢出,那么结果是math和的低位,如用一些足够大的二进制补码格式表示的。 如果发生溢出,则结果的符号与两个操作数值的math和的符号不同。
这意味着你可以依靠这种行为。
当你越过国际date线时date发生变化的原因是一样的:那里有一个不连续点。 它build立在二进制加法的本质上。
这是一个众所周知的问题,整数在二进制层表示为二进制补码 。 当你给一个二进制补码的最大值加1时,你会得到最小值。 说实话,所有的整数都是在java存在之前以这种方式performance的,改变Java语言的这种行为会给整数math增加更多的开销,而来自其他语言的混淆程序员也会增加。
当你将3
(二进制11
)加到1(二进制1
)时,你必须从右边开始把二进制1
变成0
(二进制0
),直到你得到0,你应该改成1
。 Integer.MAX_VALUE
已经填满了1
所以只剩下0
秒。
在大多数处理器上,算术指令没有模式来处理溢出错误。 他们设置了一个必须检查的标志。 这是一个额外的指令,所以可能会更慢。 为了使语言实现尽可能快,语言经常被指定为忽略错误并继续。 对于Java,行为在JLS中指定。 对于C来说,语言并没有指定行为,但是现代处理器的行为就像Java一样。
我相信有一些build议(尴尬的)Java SE 8库引发溢出,以及未签名的操作。 我相信在DSP领域stream行的行为是将值限制在最大值,所以Integer.MAX_VALUE + 1 == Integer.MAX_VALUE
[不是Java]。
我敢肯定,未来的语言将使用任意精度整数,但暂时还没有。 需要更昂贵的编译器devise才能快速运行。