int
的限制是从-2147483648到2147483647。
如果我输入
int i = 2147483648;
然后Eclipse将在“2147483648”下面提示一个红色下划线。
但如果我这样做:
int i = 1024 * 1024 * 1024 * 1024;
它编译得很好。
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
也许这是Java中的一个基本问题,但我不知道为什么第二个变体不会产生错误。
答案 0 :(得分:232)
这句话没有错;你只是将4个数字相乘并将其分配给一个int,恰好就是溢出。这与分配单个 literal 不同,后者将在编译时进行边界检查。
超出范围 literal 导致错误,而不是赋值:
System.out.println(2147483648); // error
System.out.println(2147483647 + 1); // no error
相比之下,long
文字可以正常编译:
System.out.println(2147483648L); // no error
请注意,事实上, 的结果仍在编译时计算,因为1024 * 1024 * 1024 * 1024
是constant expression:
int i = 1024 * 1024 * 1024 * 1024;
变为:
0: iconst_0
1: istore_1
请注意,结果(0
)只是被加载和存储,并且不会发生乘法。
来自JLS §3.10.1(感谢@ChrisK在评论中提出来):
如果类型
int
的十进制文字大于2147483648
(2 31 ),或者十进制文字{,则编译时错误除了作为一元减号运算符(§15.15.4)的操作数之外,{1}}出现在任何地方。
答案 1 :(得分:43)
1024 * 1024 * 1024 * 1024
和2147483648
在Java中没有相同的值。
实际上,Java中2147483648
不是值(尽管2147483648L
)。编译器实际上不知道它是什么,或者如何使用它。所以它发牢骚。
1024
是Java中的有效int,有效int
乘以另一个有效int
,始终是有效的int
。即使它与您直观期望的值不同,因为计算会溢出。
请考虑以下代码示例:
public static void main(String[] args) {
int a = 1024;
int b = a * a * a * a;
}
您是否希望这会产生编译错误?现在变得有点滑 如果我们放置一个循环3次迭代并在循环中相乘怎么办?
允许编译器进行优化,但它不能在程序执行时更改程序的行为。
有关如何实际处理此案例的一些信息:
在Java和许多其他语言中,整数将由固定数量的位组成。不符合给定位数的计算将overflow;计算基本上在Java中执行 modulus 2 ^ 32,之后将值转换回 signed 整数。
其他语言或API使用动态位数(Java中为BigInteger
),引发异常或将值设置为魔术值,例如非数字。
答案 2 :(得分:15)
我不知道为什么第二个变体没有产生错误。
您建议的行为 - 即,当计算生成的值大于可以存储在整数中的最大值时,生成诊断消息 - 是< EM>特征。对于您使用任何功能,必须考虑该功能,被认为是一个好主意,设计,指定,实施,测试,记录并发送给用户。
对于Java,该列表中的一个或多个内容未发生,因此您没有该功能。我不知道哪一个;你必须问一个Java设计师。
对于C#而言,所有这些事情确实发生了 - 大约十四年前 - 因此C#中的相应程序自C#1.0以来就产生了错误。
答案 3 :(得分:12)
除了arshajii的回答,我想再展示一件事:
赋值不会导致错误,只是使用文字。 当你尝试
long i = 2147483648;
您会注意到它也会导致编译错误,因为右侧仍然是int
- 字面值且超出范围。
所以使用int
- 值(包括赋值)的操作可能会溢出而没有编译错误(并且没有运行时错误),但编译器无法处理那些太大的文字
答案 4 :(得分:4)
答:因为这不是错误。
背景:乘法1024 * 1024 * 1024 * 1024
会导致溢出。溢出通常是一个错误。溢出发生时,不同的编程语言会产生不同的行为。例如,C和C ++称之为&#34;未定义的行为&#34;对于有符号整数,行为定义为无符号整数(只要结果为负数,取数学结果,添加UINT_MAX + 1
,只要结果大于UINT_MAX + 1
,减去UINT_MAX
)。
对于Java,如果具有int
值的操作的结果不在允许的范围内,则概念上Java添加或减去2 ^ 32,直到结果在允许的范围内。因此,该陈述完全合法且没有错误。它只是没有产生你可能希望的结果。
你肯定会争论这种行为是否有用,以及编译器是否应该给你一个警告。我个人说,警告非常有用,但错误是不正确的,因为它是合法的Java。