Java新手问询:short与long变量溢出差异及强制转换必要性
为什么long和short在溢出场景下表现不同?
嘿,这个问题的核心其实是Java整数运算的自动类型提升和溢出行为在不同类型下的差异,我给你拆解得明明白白:
先搞懂Java整数运算的基础规则
咱们先达成一个共识:当你对byte、short、int这些整数类型做运算时,JVM会自动把它们提升为int类型来执行计算——除非你显式地把某个操作数强制转换为更大的类型(比如long),否则所有中间计算步骤都会被限制在int的范围内。一旦计算结果超过int的取值上限(2^31-1,也就是2147483647)或者低于下限(-2^31,也就是-2147483648),就会发生溢出,结果会变成一个看似无意义的负数(因为整数在Java里是补码存储的)。
关于long类型的两个例子差异
先看你给出的long计算代码:
第一个正确的例子:
long myLong = (long)(50_000 + 10 * (long)(myByte + myShort + myInt));
这里的关键是内层的(long)强制转换:
myByte + myShort + myInt被强制转换成了long类型,所以这个求和结果是一个long值(2000155100,远小于long的最大值);- 接下来
10 * 这个long值的计算也会在long范围内进行,结果是20001551000; - 加上50000之后还是
long类型,最后外层的(long)转换其实是多余的,但不影响结果; - 整个过程没有溢出,所以最终得到正确的结果
20001601000。
第二个溢出的例子:
long myLong2 =(long)(50_000 + 10 * (myByte + myShort + myInt));
这里没有给内层求和加(long)转换,问题就出在这里:
myByte + myShort + myInt被自动提升为int计算,结果是2000155100(这个数刚好没超过int的上限,暂时没问题);- 但接下来
10 * 这个int值的计算还是在int范围内进行,2000155100*10=20001551000——这个数远远超过了int的最大值2147483647,直接发生溢出,变成了负数-1473235480; - 然后加上50000,还是基于溢出后的
int值计算,结果依然是负数; - 最后外层的
(long)转换只是把这个负数转成了long类型,所以结果就是你看到的-1473235480。
简单说:第一个例子把内层计算提前升到long,避免了溢出;第二个例子全程用int计算,中间步骤溢出了,最后转long也救不回来。
关于short类型的两个例子结果相同
再看short的计算代码:
两个例子的代码:
short myShortTest = (short)(50_000 + 10*(short)(myByte + myInt +myShort)); short myShortTest2 = (short)(50_000 + 10*(myByte + myInt +myShort));
为什么这两个结果都是13800?咱们拆开看:
第二个例子(无内层转换):
myByte + myInt + myShort自动提升为int计算,结果是2000155100;- 乘以10得到20001551000(
int溢出,但没关系,因为最后要转short); - 加上50000得到20001601000;
- 最后转
short时,Java会取这个数的低16位(因为short是16位类型),计算后得到13800。
第一个例子(有内层
(short)转换):myByte + myInt + myShort先转成short——但这个求和结果2000155100远大于short的最大值32767,所以转short时已经溢出,得到的是这个数的低16位(也就是-3620);- 然后10*-3620=-36200,加上50000得到13800;
- 最后转
short还是13800。
简单说:不管中间有没有转short,最后一步都是把最终结果的低16位取出来当short值,刚好两次计算的最终结果低16位都是13800,所以输出相同。
总结一下:
long的差异是因为中间计算是否在大类型中进行,溢出发生在int阶段就会导致错误结果;short的结果相同是因为最终都会取低16位,中间的溢出不影响最终的截断结果。
内容的提问来源于stack exchange,提问作者itay k
相关产品推荐
相关产品推荐

