ArithmeticException 不会因 2^32 内的溢出而抛出

ArithmeticException not thrown for overflow within 2^32

我知道分配一个大于 2^32 的数字有机会生成一个 ArithmeticException 但今天我在编程时:

int x = 65535
System.out.println(x * x);

Output: -131071

所以没有例外,只是意外的结果。

溢出

乘法不受保护防止溢出。

你在这里看到的是整数溢出。如果你取最大的整数 Integer.MAX_VALUE 并加上 1 你得到最小的整数 INTEGER.MIN_VALUE:

int value = Integer.MAX_VALUE;
System.out.println(value);  // 2147483647
value++;
System.out.println(value);  // -2147483648

同样的情况也发生在这里,因为

65_535 * 65_535 = 4_294_836_225 > 2_147_483_647

范围int

In Java int 是一个带符号的 32 位值。特别是 not unsigned.

                 |    min-value   |   max-value   |
-----------------|----------------|---------------|
   signed-32-bit |          -2^31 |      2^31 - 1 |
                 | -2_147_483_648 | 2_147_483_647 |
-----------------|----------------|---------------|
 unsigned-32-bit |        2^0 - 1 |      2^32 - 1 |
                 |              0 | 4_294_967_295 |

异常

乘法 不会 抛出 ArithmeticException。据我所知,只有除以 0 时才会发生这种情况,因为根据定义这是不可能的。另请参阅异常的 documentation

对于受保护的乘法,请考虑使用 Math#multiplyExact (documentation)。

我认为您对 int 类型有多少位感到困惑,它是 32 位到它代表的数字之间:

 -2 147 483 648 <= int <= 2 147 483 647

因为它也代表负数,所以只能代表2^31

在java中,int是原始的带符号的32位,它有

max value = 2.147.483.647

min value = -2.147.483.648

你的乘法结果是 4.294.836.225。

因为你使用 int 基本类型,如果它 overflows,它会回到 minimum value 并从那里继续。如果它 underflows,它会返回到 maximum value 并从那里继续。

如果你想捕获异常,你可以使用Math class 或 Integer class.

        try
        {
          int c = Math.multiplyExact(a,b);
        } catch (ArithmeticException ex)
        {
            System.err.println("int is too small, falling back to long.");;
        }