Java中将int数据运算结果赋值给long发生溢出问题

博主今日在一道算法题中调用自定义的快速幂方法时,提交始终无法AC。但算法思路和实现过程万无一失,经过仔细排查,终于发现了一个一直以来都被忽视掉的Java基本数据向上转型溢出问题。

话不多说,直接上代码:

public class Int2LongOverflow {
    public static void main(String[] args) {
        // Integer.MAX_VALUE = 2147483647
        int a = Integer.MAX_VALUE;
        int b1 = 1;
        long sum1 = a + b1;

        long sum2 = 2147483647 + 1;

        long b2 = 1;
        long sum3 = a + b2;

        long sum4 = 2147483647 + 1L;

        System.out.println("sum1 = " + sum1);
        System.out.println("sum2 = " + sum2);
        System.out.println("sum3 = " + sum3);
        System.out.println("sum4 = " + sum4);
    }
}

在公布答案之前,大家思索一下,是不是sum1, sum2, sum3, sum4均输出2147483648呢?

好了,下面是代码运行结果:

sum1 = -2147483648
sum2 = -2147483648
sum3 = 2147483648
sum4 = 2147483648

看似sum1, sum2, sum3, sum4均计算2147483647 + 1的结果,并且结果用long类型接收,但为什么会有两种不同计算结果呢?

  1. sum1计算的是a + b1,其中ab1均为int类型数据。因此,计算顺序是这样的:首先取表达式中最大的类型暂存计算结果,也就是int类型暂存a + b1的结果,显然会发生溢出,暂存的结果就为-2147483648;然后再将暂存的结果赋值给sum1,其中会向上隐式转型,于是sum1 = -2147483648
  2. sum2计算的是两个字面量值的和。在Java中,纯数字字面量默认类型为int(在整数后加L表示long类型,例如12L表示long类型的12),因此,sum2的计算效果同sum1
  3. sum3sum1唯一的区别就是,其中b2的类型变为long(值保持不变)。因此在计算时,会将a向上转型为long,再做long类型之间的运算,运算结果为long类型,最后再赋值给sum3。这一系列操作自然不会发生溢出。
  4. sum4表达式中的字面量1L为long类型,计算效果同sum3,不会发生溢出。

总结:
在Java中,如果赋值语句的右边是表达式,可以将该语句看成三个执行过程。

  1. 将表达式中所有变量或字面量隐式向上转型为其中的最大类型;
  2. 用1中的最大类型暂存计算结果;
  3. 将暂存的结果赋值给左侧变量,如果暂存类型与左侧变量类型不一致,需要做显式(向下转型)或隐式(向上转型)的类型转换。

你可能感兴趣的:(Java)