long thirtyDayInMillis = 30 * 24 * 60 * 60 * 1000;
它应返回2592000000
,但会返回-1702967296
。
但如果我将声明分成两个陈述。
long dayInMillis = 24 * 60 * 60 * 1000;
long thirtyDayInMillis = 30 * dayInMillis;
返回正确的值。
为什么它会为-1702967296
返回30 * 24 * 60 * 60 * 1000
?
答案 0 :(得分:12)
默认情况下,Java中的数字文字是int
。因此,第一个乘法的各个部分都是int
s,而不是long
s,因此它们会溢出(数字太大而无法存储在int
中)。当你分解它时,你会在它溢出之前将值转换为long
。
你可以通过在文字中添加L
来解决这个问题,使它们变长;只有第一个是您真正需要的,因为30L * 24
的结果将是long
,依此类推:
thirtyDayInMillis = 30L * 24 * 60 * 60 * 1000;
请注意,我将L
放在文字的第一个上。这是因为乘法从左到右进行,所以我们要从一开始就确保我们使用的是long
值,而不是int
值。例如,它的处理方式如下:
thirtyDayInMillis = (((30L * 24) * 60) * 60) * 1000;
首先30L * 24
完成,然后结果为* 60
,依此类推。因此,如果早期的那些(没有L
仍然以int
值完成)溢出,结果将是错误的。
你的特定表达式在最后一次乘法之前不会溢出,但让我们使用先前会溢出的值:
thirtyDayInMillis = 1000 * 24 * 6000 * 7000 * 30;
这给了我们(不正确的)结果-864731136
而不是30240000000000
。现在让我们把L
放在错误的地方:
thirtyDayInMillis = 1000 * 24 * 6000 * 7000 * 30L;
// L in wrong place ----------------------------^
我们得到-39519436800
。把它放在正确的地方:
thirtyDayInMillis = 1000L * 24 * 6000 * 7000 * 30;
...我们得到30240000000000
。
答案 1 :(得分:2)
您正面临整数溢流最常见的问题,
使用此
long thirtyDayInMillis = 1L * 30 * 24 * 60 * 60 * 1000;
根据documentation of Lexical Literals提到的,
文字的类型确定如下:
- 以L或l结尾的整数文字(§3.10.1)的类型很长(§4.2.1)。
- 任何其他整数文字的类型是int(§4.2.1)。
因此,您的表达式30 * 24 * 60 * 60 * 1000
被评估为int
原始数据类型,因为任何数值都未提及l
或L
。结果是 2,592,000,000
即在二进制文件中,它是 1001 1010 0111 1110 1100 1000 0000 0000
,而int
是32位,因此Example 4.2.2-1. Integer Operations中提到的32位如此低,导致 {{ 1}} ,因为最重要的位用于表示符号。
答案 2 :(得分:1)
你应该这样做:
long thirtyDayInMillis = 30L * 24 * 60 * 60 * 1000;
Java中数字的默认值为int
。因此,当您执行30 * 24 * 60 * 60 * 1000
时,您将获得int
计算,这会溢出。
请参阅docs:
如果整数字面以字母 L 或 l 结尾,则其长度为long; 否则为int 类型。建议您使用鞋面 大小写字母L因为小写字母l很难区分 从数字1。
答案 3 :(得分:0)
尝试long thirtyDayInMillis = 30 * 24 * 60 * 60 * 1000L;
默认情况下,最后将其视为int
添加L
,让编译器知道您正在传递long
值,但正如Tim B指出*它的危险性因为30 * 24 * 60 * 60将以整数形式处理,仅用于最后一次乘法转换为long *
这样做
long thirtyDayInMillis = 30L * 24 * 60 * 60 * 1000;
答案 4 :(得分:0)
这是因为你正在乘以最大值为2147483647的整数 等式的右边保持int类型。 因此,只需尝试通过向其添加“l”来生成long类型的乘数之一,您将获得正确的结果 的 e.g。 long threeDayInMillis = 30l * 24 * 60 * 60 * 1000;