Puzzle 86: Poison-Paren Litter

括号有毒-_-!

以下是本问题用到的两个类:

public class PoisonParen {
    int i = -(2147483648);
}
public class PoisonParen {
    long j = -(9223372036854775808L);
}

无论是 Eclipse 还是 NetBeans 都提醒了数值过大,可是 -2147483648 = -2^31 == Integer.MIN_VALUE,为啥会出现这样的情况呢?

以上是 Eclipse 的

以上是 NetBeans 的

嗯,把括号去掉试试,好了,IDE 不报错,完全正常!

看来罪魁祸首是那对括号了,对,确实是它!一般情况下,加括号都是没有害处的,但这里,因为加了括号,就相当于写了一个 int 整数:2147483648,这个数比 Integer.MAX_VALUE 还大1,当然会报错。

Java语言中整数的范围

在具体的语言中,比如 Java,整数是用范围的,亦Java的整数只是数学中定义的整数的一个子集,不然也不要搞个长整数(Long)了,虽然 Long 还是数学中定义的整数的一个子集,它们具体的取值范围如下:

Integer.MAX_VALUE = 2147483647 = 231-1
Integer.MIN_VALUE = -2147483648 = -231
Long.MAX_VALUE = 9223372036854775807 = 263 -1
Long.MIN_VALUE = -9223372036854775808 = -263

为何是这个范围?考虑到 int 是32位,long 是64位,数字位数太多,这里假设用四位来表示整数,观察它的表示情况:

以上表示的数的范围是 -8 ~ 7,即-23 ~ 23-1,可见在计算机中通过补码表示整数的话,用 n 位的话,表示的范围为 -2n-1 ~ 2n-1-1.

  1. 相关的puzzle:Puzzle 33, Puzzle 64
  2. JLS 3.10.1,值得留意的是,这个规范只是说明了现象,只是描述性的,并不解释原因的,而具体原因,要参照本文中“Java语言中整数的范围”的说明。
  3. JAVA基础学习总结---原码、补码、反码以及基本数据类型 (by willzzs),这篇文里简单的提到了,补码即为反码加1. 而在JLS 15.15.4中更提到“For all integer values x, -x equals (~x)+1”。显然後者更为简单。