Java 不会对 int 或 long 原始类型的整数溢出做任何事情,并且忽略正整数和负整数的溢出。
这个答案首先描述了整数溢出,给出了一个例子来说明它是如何发生的,即使是在表达式评估中的中间值,然后给出了资源的链接,这些资源提供了防止和检测整数溢出的详细技术。
导致意外或未检测到溢出的整数运算和表达式是常见的编程错误。意外或未检测到的整数溢出也是一个众所周知的可利用安全问题,尤其是当它影响数组、堆栈和列表对象时。
溢出可以在正或负方向发生,其中正值或负值将超出所讨论的原始类型的最大值或最小值。在表达式或运算求值期间,中间值可能会发生溢出,并影响最终值应在范围内的表达式或运算的结果。
有时负溢出被错误地称为下溢。下溢是当一个值比表示允许的更接近零时发生的情况。下溢发生在整数算术中并且是预期的。当整数计算介于 -1 和 0 或 0 和 1 之间时,会发生整数下溢。小数结果会被截断为 0。这是正常的,并且在整数运算中是预期的,不被视为错误。但是,它可能导致代码抛出异常。如果整数下溢的结果用作表达式中的除数,则一个示例是“ArithmeticException: / by zero”异常。
考虑以下代码:
int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;
这导致 x 被分配 0 并且随后对 bigValue / x 的评估引发异常“ArithmeticException: / by zero”(即除以零),而不是 y 被分配值 2。
x 的预期结果为 858,993,458,小于最大 int 值 2,147,483,647。但是,计算 Integer.MAX_Value * 2 的中间结果将是 4,294,967,294,它超过了最大 int 值并且根据 2s 补码整数表示为 -2。 -2 / 5 的后续评估评估为 0,它被分配给 x。
将用于计算 x 的表达式重新排列为一个表达式,该表达式在求值时会在乘法之前先除,代码如下:
int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;
导致 x 被分配 858,993,458 和 y 被分配 2,这是预期的。
bigValue / 5 的中间结果是 429,496,729,它不超过 int 的最大值。随后对 429,496,729 * 2 的评估不超过 int 的最大值,并且预期的结果被分配给 x。然后对 y 的评估不会除以零。 x 和 y 的评估按预期工作。
Java 整数值被存储为 2s 补码有符号整数表示形式并按照其运行。当结果值大于或小于最大或最小整数值时,将产生一个 2 的补码整数值。在没有明确设计为使用 2s 补码行为的情况下,这是最普通的整数算术情况,生成的 2s 补码值将导致编程逻辑或计算错误,如上例所示。一篇出色的维基百科文章在这里描述了 2s 补码二进制整数:Two's complement - Wikipedia
有一些技术可以避免无意的整数溢出。 Techinques 可以分类为使用前置条件测试、向上转换和 BigInteger。
前置条件测试包括检查进入算术运算或表达式的值,以确保这些值不会发生溢出。编程和设计需要创建测试以确保输入值不会导致溢出,然后确定如果输入值出现会导致溢出时该怎么做。
向上转换包括使用更大的原始类型来执行算术运算或表达式,然后确定结果值是否超出整数的最大值或最小值。即使使用向上转换,操作或表达式中的值或某些中间值仍有可能超出向上转换类型的最大值或最小值并导致溢出,这也不会被检测到并且会导致意外和不希望的结果。通过分析或前置条件,当不上转型的预防不可能或不切实际时,可能有可能通过上转型来防止溢出。如果所讨论的整数已经是 long 原始类型,那么 Java 中的原始类型就无法向上转换。
BigInteger 技术包括将 BigInteger 用于算术运算或使用使用 BigInteger 的库方法的表达式。 BigInteger 不会溢出。如有必要,它将使用所有可用内存。它的算术方法通常只比整数运算效率略低。使用 BigInteger 的结果仍有可能超出整数的最大值或最小值,但是在导致结果的算术中不会发生溢出。如果 BigInteger 结果超出所需原始结果类型(例如 int 或 long)的最大值或最小值,编程和设计仍需要确定该怎么做。
卡内基梅隆软件工程学院的 CERT 计划和 Oracle 为安全 Java 编程创建了一套标准。标准中包括防止和检测整数溢出的技术。该标准在此处作为可免费访问的在线资源发布:The CERT Oracle Secure Coding Standard for Java
描述并包含防止或检测整数溢出的编码技术的实际示例的标准部分在这里:NUM00-J. Detect or prevent integer overflow
还提供 The CERT Oracle Secure Coding Standard for Java 的书本形式和 PDF 形式。