Java整数运算溢出会静默回绕,需从数据范围、典型场景和防御手段三方面应对:各类型有严格补码边界;溢出常发生在计算过程而非赋值;可用更大类型、Exact API、手动检查或BigInteger防范。

Java 基础类型运算不会自动报错,溢出时静默回绕——这是很多初学者踩坑的根源。关键不是“会不会溢出”,而是“什么时候会、为什么发生、怎么提前拦住”。下面从数据范围、典型溢出场景、实用防御手段三方面说清楚。
各整数类型的真实取值边界
Java 所有整数类型都用二进制补码表示,最高位是符号位。实际能存的数字不是“看起来多大”,而是由位数严格决定:
- byte:1 字节(8 位),范围 -128 ~ 127(即 -2⁷ ~ 2⁷-1)
- short:2 字节(16 位),范围 -32768 ~ 32767(-2¹⁵ ~ 2¹⁵-1)
- int:4 字节(32 位),范围 -2147483648 ~ 2147483647(-2³¹ ~ 2³¹-1)
- long:8 字节(64 位),范围 -9223372036854775808 ~ 9223372036854775807(-2⁶³ ~ 2⁶³-1)
注意:这些不是近似值,而是精确上下限。比如 int 最大值 +1 不是报错,而是直接变成最小值 -2147483648。
算术运算中真正危险的溢出点
溢出常发生在“计算过程”而非“赋值瞬间”。即使左边变量是 long,若右边两个操作数都是 int,加法/乘法仍按 int 算——结果先溢出,再转成 long,已晚。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
加法陷阱:
int a = Integer.MAX_VALUE; long b = a + 1;→ b 实际是 -2147483648L(因为 a+1 先按 int 算,溢出后才转 long) -
乘法陷阱:
int x = 100000; int y = 100000; int z = x * y;→ 结果是 1410065408(不是 10000000000),因 100000×100000 超出 int 范围 -
反转整数类题目:如 LeetCode 7 题,
result = result * 10 + digit这一步极可能在乘 10 后就溢出,必须在计算前检查
四种靠谱的防溢出策略
不靠运气,靠设计。根据场景选合适方法:
-
用更大的基础类型预判:若原始数据是 int,但中间结果可能超限,直接声明为 long 参与运算,并确保字面量带
L(如10000000000L),避免编译器误判为 int -
用 Java 8+ 的精确运算 API:
Math.addExact(a, b)、Math.multiplyExact(a, b)等,溢出时抛ArithmeticException,适合需要强校验的业务逻辑 -
手动边界检查:加法前判断
a > 0 && b > 0 && a > Integer.MAX_VALUE - b;乘法前判断b != 0 && a > Integer.MAX_VALUE / b(注意除零和负数) -
交给 BigInteger 处理任意精度:当数值大小完全不可控(如密码学、金融大额计算),用
BigInteger.valueOf(x).multiply(BigInteger.valueOf(y)),无溢出风险,但有性能开销
一个典型修复示例:整数反转
错误写法:
int result = 0;
while (x != 0) {
result = result * 10 + x % 10; // 这里可能溢出,且无法挽回
x /= 10;
}正确思路(检查前置):
int result = 0;
while (x != 0) {
int digit = x % 10;
// 检查 result * 10 是否会溢出
if (result > Integer.MAX_VALUE / 10 ||
(result == Integer.MAX_VALUE / 10 && digit > 7)) return 0;
if (result < Integer.MIN_VALUE / 10 ||
(result == Integer.MIN_VALUE / 10 && digit < -8)) return 0;
result = result * 10 + digit;
x /= 10;
}本质是:在每一步乘 10 前,确认当前 result 是否已逼近边界,再结合个位 digit 判断是否越界。

















