Java long字面量与final常量乘法结果为何不一致?
运行结果差异原因
Java中算术运算的类型由参与运算的操作数本身的静态类型决定,和最终赋值的变量类型、变量是否被final修饰没有直接关联,两个结果不一致的核心原因是两次乘法的操作数类型完全不同:
c的计算逻辑(溢出得到负数)
- 代码中无后缀的整数字面量
123123默认是32位int类型,取值范围仅为-2147483648 ~ 2147483647。 - 表达式
123123*123123*123123的三个操作数全是int类型,因此整个乘法全程按int规则运算:第一步计算123123 * 123123得到15159273129,已经远超int最大值,直接触发int溢出,后续乘法用溢出后的int值继续计算,最终得到int结果-162426261。 - 这个溢出后的int结果最后才会隐式转换为long赋值给c,溢出早已发生,和是否编译期计算无关——哪怕编译期做常量折叠,也是按int类型算完溢出的结果再赋值,结果不会改变。
d的计算逻辑(得到正确结果)
- 变量
b是被final long修饰的编译期常量,静态类型明确是64位long,long的取值范围最大可达9223372036854775807,完全可以容纳123123的三次方结果。 - 表达式
b*b*b的三个操作数全是long类型,乘法全程按long规则运算,不会触发int层面的溢出,最终得到正确值1866455185461867。这个计算同样会在编译期完成常量折叠,只是运算采用的类型是long,结果自然正确。
原有认知的偏差
你之前认为「final修饰long变量后编译期运算结果应该一致」的问题,是混淆了常量折叠的规则和类型提升规则:
- 编译期确实会对final基本类型常量、字面量表达式直接计算结果,但计算时严格遵守Java的类型规则,不会因为最终要赋值给long变量,就自动把表达式里的int操作数提升为long。
- 如果要让c的结果和d一致,只需要给第一个字面量加上long后缀
L,把第一个操作数标记为long类型即可,比如写成final long c = 123123L * 123123 * 123123;,后续的int操作数会自动提升为long参与运算,就不会出现int溢出了。
内容的提问来源于stack exchange,提问作者bc a
相关产品推荐
相关产品推荐

