java基本类型溢出默认静默绕回,非bug而是二进制自然行为;需依场景选策略:用math.exact系列抛异常、升阶long校验、前置约束或biginteger,避免double存精确值及盲目升long。

Java 中基本数据类型发生数值溢出时,默认不报错、不提示、不中断执行,而是按补码规则静默“绕回”——比如 int 达到 2147483647 后加 1,结果直接变成 -2147483648。这不是 bug,而是底层二进制运算的自然行为。关键不是“防不住”,而是选对策略,在合适场景用合适手段。
明确各类型的精确边界值
每种整型都有固定位宽和严格上下限,超出即溢出:- byte:8 位,范围 -128 ~ 127
- short:16 位,范围 -32768 ~ 32767
- int:32 位,范围 -2147483648 ~ 2147483647(最常出问题)
- long:64 位,范围 -9223372036854775808 ~ 9223372036854775807
- char:16 位无符号,0 ~ 65535
- float/double:不绕回,但存在精度丢失(如 `0.1 + 0.2 != 0.3`),不能用于精确计数或 ID 存储
避开隐式溢出陷阱
溢出常发生在**计算过程**,而非赋值那一刻。常见误写:- `int a = Integer.MAX_VALUE; long b = a + 1;` → 先按 int 算 `a+1`,已溢出为 -2147483648,再转 long,结果仍是负数
- `int x = 100000; int y = 100000; int z = x * y;` → `100000×100000 = 10^10`,远超 int 上限,结果是 `1410065408`(错误值)
- `24 * 3600 * 1000 * days`(日期毫秒计算)→ 所有操作数是 int,30 天就溢出,导致时间倒退
四类实用防护方式
根据业务重要性、性能要求和代码可维护性选择:- Math.exact 系列(推荐日常使用):`Math.addExact(a, b)`、`Math.multiplyExact(a, b)` 等,溢出时明确抛 `ArithmeticException`,异常信息清晰,适合订单计数、库存校验等关键路径
-
升阶计算 + 范围校验(性能敏感场景):先转 `long` 运算,再判断是否仍在 `int` 范围内,例如:
`long temp = (long) a + b; if (temp Integer.MAX_VALUE) { /* 溢出处理 */ }` - 前置输入约束(防御式设计):对用户输入、配置项、循环变量设安全上限,比如限制数量 ≤ `Integer.MAX_VALUE / 10`,避免后续乘法必然溢出
- BigInteger(不容错场景):金融结算、大数算法、全局唯一 ID 生成等,支持任意精度,但对象开销大,勿滥用在高频简单计数中
不该做的几件事
- 别用 `double` 存订单号、身份证号或金额——它无法精确表示多数十进制小数
- 别靠“换 long 就万事大吉”——如果原始逻辑本身会累加几十亿次,`long` 终究也会满;要结合业务周期评估真实上限
- 别用 `(int) 3000000000L` 强转——静默截断成负数;应改用 `Math.toIntExact(3000000000L)`,溢出时主动报错
- 数组长度、索引、`List.size()` 返回 `int`,超 21 亿元素会溢出;高并发长周期服务中,考虑分片或自定义 long 容器
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











