现在的位置: 首页 > 综合 > 正文

Java中的无声杀手 – Integer Overflow, 当心 !

2013年12月14日 ⁄ 综合 ⁄ 共 1160字 ⁄ 字号 评论关闭

原文:http://www.mkyong.com/java/javas-silent-killer-buffer-overflow-careful/

不管你信不信,Java也有Integer overflow的问题。我不确定这个词儿是否是正确地描述这个问题的词儿,你也许可以给我一点建议微笑

OK,看一下下面的程序。这个程序打印出每天有多少微妙数。

public class Test {

    public static void main(String[] args) {

        final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;

        System.out.println("MICROS_PER_DAY : " + MICROS_PER_DAY);

    }

}

输出结果:

MICROS_PER_DAY : 500654080

Oh.. 答案是500654080. 等等.. 这个答案正确嘛?正确的答案应该是86400000000 !!! 为什么Java给我了一个不精确的结果? 这个结果是从哪来的? 到底发生了什么?

我相信这是由于“int” overflow引起的。是的,“long MICROS_PER_DAY”变量是有足够的空间来保存像86400000000这样大的数的,但是这个大数无法用"int"来保存! 一个“int”可以保存的最大的数是2147483647。仔细看看上面的程序,整个的数学运算过程都是以“int”进行的,只是运算的结果被转型成一个long并且被赋值给“long MICROS_PER_DAY”变量. 按照Java语言规范[JLS 5.1.2], the promotion from int to long
is cited as widening primitive conversion which preserves the (incorrect) numerical value.

不管怎样,我们可以避免上面的无声杀手,通过将第一个整数显示的转成/声明成“long”,以使得运算过程变成以long进行的数学运算。

public class Test {
    public static void main(String[] args) {
        final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
        System.out.println("MICROS_PER_DAY : " + MICROS_PER_DAY);
    }
}

输出结果:

MICROS_PER_DAY : 86400000000

这回上面的程序输出了期望的结果86400000000。



结论

这个bug非常地难发现或被人们所知。如果有人在金融系统中犯了这样的错误,我真无法想像后果。我唯一的建议是当进行两个不同类型的原始类型运算时要显示地转型。 在任何运算中避免widening primitive conversion。

抱歉!评论已关闭.