Java 为什么 int i = 1024 * 1024 * 1024 * 1024 编译没有错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24676375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does int i = 1024 * 1024 * 1024 * 1024 compile without error?
提问by WUJ
The limit of int
is from -2147483648 to 2147483647.
的限制int
是从 -2147483648 到 2147483647。
If I input
如果我输入
int i = 2147483648;
then Eclipse will prompt a red underline under "2147483648".
然后Eclipse会在“2147483648”下提示一个红色下划线。
But if I do this:
但如果我这样做:
int i = 1024 * 1024 * 1024 * 1024;
it will compile fine.
它会编译得很好。
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Maybe it's a basic question in Java, but I have no idea why the second variant produces no error.
也许这是 Java 中的一个基本问题,但我不知道为什么第二个变体不会产生错误。
采纳答案by arshajii
There's nothing wrong with that statement; you're just multiplying 4 numbers and assigning it to an int, there just happens to be an overflow. This is different than assigning a single literal, which would be bounds-checked at compile-time.
这句话没有错;您只是将 4 个数字相乘并将其分配给一个 int,恰好发生了溢出。这与分配单个文字不同,后者将在编译时进行边界检查。
It is the out-of-bounds literalthat causes the error, not the assignment:
导致错误的是越界文字,而不是赋值:
System.out.println(2147483648); // error
System.out.println(2147483647 + 1); // no error
By contrast a long
literal would compile fine:
相比之下,long
文字可以很好地编译:
System.out.println(2147483648L); // no error
Note that, in fact, the result isstill computed at compile-time because 1024 * 1024 * 1024 * 1024
is a constant expression:
需要注意的是,其实,结果是仍然在编译时计算的,因为1024 * 1024 * 1024 * 1024
是一个常数表达式:
int i = 1024 * 1024 * 1024 * 1024;
becomes:
变成:
0: iconst_0
1: istore_1
Notice that the result (0
) is simply loaded and stored, and no multiplication takes place.
请注意,结果 ( 0
) 只是简单地加载和存储,没有进行乘法运算。
From JLS §3.10.1(thanks to @ChrisK for bringing it up in the comments):
来自JLS §3.10.1(感谢@ChrisK 在评论中提出):
It is a compile-time error if a decimal literal of type
int
is larger than2147483648
(231), or if the decimal literal2147483648
appears anywhere other than as the operand of the unary minus operator (§15.15.4).
如果类型的十进制文字
int
大于2147483648
(2 31),或者十进制文字2147483648
出现在除作为一元减号运算符 ( §15.15.4)的操作数之外的任何地方,则会出现编译时错误。
回答by Eric Lippert
I have no idea why the second variant produces no error.
我不知道为什么第二个变体不会产生错误。
The behaviour that you suggest -- that is, the production of diagnostic message when a computation produces a value that is larger than the largest value that can be stored in an integer-- is a feature. For you to use any feature, the feature must be thought of, considered to be a good idea, designed, specified, implemented, tested, documented and shipped to users.
您建议的行为——即,当计算产生的值大于可以存储在整数中的最大值时产生诊断消息——是一个特性。要使用任何功能,必须考虑该功能,认为该功能是一个好主意,设计、指定、实施、测试、记录并交付给用户。
For Java, one or more of the things on that list did not happen, and therefore you don't have the feature. I don't know which one; you'd have to ask a Java designer.
对于 Java,该列表中的一项或多项事情没有发生,因此您没有该功能。我不知道是哪一个;你得问一个 Java 设计师。
For C#, all of those things did happen -- about fourteen years ago now -- and so the corresponding program in C# has produced an error since C# 1.0.
对于 C#,所有这些事情都确实发生了——大约在 14 年前——所以 C# 中的相应程序自 C# 1.0 以来就产生了错误。
回答by piet.t
In addition to arshajii's answer I want to show one more thing:
除了 arshajii 的回答,我还想再说明一件事:
It is not the assignmentthat causes the error but simply the use of the literal. When you try
导致错误的不是赋值,而只是文字的使用。当你尝试
long i = 2147483648;
you'll notice it also causes a compile-error since the right hand side still is an int
-literal and out of range.
您会注意到它还会导致编译错误,因为右侧仍然是int
-literal 并且超出范围。
So operations with int
-values (and that's including assignments) may overflow without a compile-error (and without a runtime-error as well), but the compiler just can't handle those too-large literals.
因此,带有int
-values 的操作(包括赋值)可能会在没有编译错误(也没有运行时错误)的情况下溢出,但编译器无法处理那些过大的文字。
回答by Cruncher
1024 * 1024 * 1024 * 1024
and 2147483648
do not have the same value in Java.
1024 * 1024 * 1024 * 1024
并且2147483648
在 Java 中没有相同的值。
Actually, 2147483648
ISN'T EVEN A VALUE(although 2147483648L
is) in Java. The compiler literally does not know what it is, or how to use it. So it whines.
实际上,在 Java 中2147483648
甚至不是一个值(尽管2147483648L
是)。编译器实际上不知道它是什么,也不知道如何使用它。所以它发出呜呜声。
1024
is a valid int in Java, and a valid int
multiplied by another valid int
, is always a valid int
. Even if it's not the same value that you would intuitively expect because the calculation will overflow.
1024
是 Java 中的有效 int,并且有效int
乘以另一个有效int
,始终是有效int
。即使它与您直觉上期望的值不同,因为计算会溢出。
Example
例子
Consider the following code sample:
考虑以下代码示例:
public static void main(String[] args) {
int a = 1024;
int b = a * a * a * a;
}
Would you expect this to generate a compile error? It becomes a little more slippery now.
What if we put a loop with 3 iterations and multiplied in the loop?
您是否希望这会产生编译错误?现在变得有点滑了。
如果我们将一个循环进行 3 次迭代并在循环中相乘会怎样?
The compiler is allowed to optimize, but it can't change the behaviour of the program while it's doing so.
允许编译器进行优化,但它不能在执行此操作时更改程序的行为。
Some info on how this case is actually handled:
有关如何实际处理此案的一些信息:
In Java and many other languages, integers will consist of a fixed number of bits. Calculations that don't fit in the given number of bits will overflow; the calculation is basically performed modulus2^32 in Java, after which the value is converted back into a signedinteger.
在 Java 和许多其他语言中,整数将由固定数量的位组成。不适合给定位数的计算将溢出;计算基本上是在 Java 中执行模数2^32,然后将值转换回有符号整数。
Other languages or API's use a dynamic number of bits (BigInteger
in Java), raise an exception or set the value to a magic value such as not-a-number.
其他语言或 API 使用动态位数(BigInteger
在 Java 中)、引发异常或将值设置为魔术值,例如非数字。
回答by gnasher729
A:Because it is not an error.
A:因为这不是错误。
Background:The multiplication 1024 * 1024 * 1024 * 1024
will lead to an overflow. An overflow is very often a bug. Different programming languages produce different behavior when overflows happen. For example, C and C++ call it "undefined behavior" for signed integers, and the behavior is defined unsigned integers (take the mathematical result, add UINT_MAX + 1
as long as the result is negative, subtract UINT_MAX + 1
as long as the result is greater than UINT_MAX
).
背景:乘法1024 * 1024 * 1024 * 1024
会导致溢出。溢出通常是一个错误。发生溢出时,不同的编程语言会产生不同的行为。例如,C 和 C++ 称其为有符号整数的“未定义行为”,而行为被定义为无符号整数(取数学结果,UINT_MAX + 1
只要结果为负就相加UINT_MAX + 1
,只要结果大于 就相减UINT_MAX
)。
In the case of Java, if the result of an operation with int
values is not in the allowed range, conceptually Java adds or subtracts 2^32 until the result is in the allowed range. So the statement is completely legal and not in error. It just doesn't produce the result that you may have hoped for.
在 Java 的情况下,如果一个带有int
值的操作的结果不在允许的范围内,从概念上 Java 加或减 2^32,直到结果在允许的范围内。所以该声明是完全合法的,没有错误。它只是不会产生您可能希望的结果。
You can surely argue whether this behavior is helpful, and whether the compiler should give you a warning. I'd say personally that a warning would be very useful, but an error would be incorrect since it is legal Java.
您当然可以争论这种行为是否有帮助,以及编译器是否应该给您警告。我个人认为警告会非常有用,但错误是不正确的,因为它是合法的 Java。