位运算优化乘除仅适用于非负整数的2的幂次场景,需警惕溢出、符号行为及优先级陷阱;JIT已自动优化,手动替换无实际收益且降低可读性。

位运算做乘除法不是万能优化,只在特定整数场景下有效,且必须确保不溢出、无符号或已知符号行为。
用 << 和 >> 替代乘除 2 的幂次时,必须确认操作数非负
Java 中 >> 是带符号右移,负数会补 1,结果不符合数学除法;>>> 才是无符号右移。比如 -8 >> 1 得 -4(看似对),但 -9 >> 1 得 -5,而 -9 / 2 向零取整应为 -4 —— 结果错。
- 正整数乘除 2 的幂:可用
<</>>,如x << 3≡x * 8,x >> 2≡x / 4(向下取整) - 要严格匹配
/的向零语义?别用位移,老实用/ - 若确定是无符号逻辑(如处理字节流、哈希计算),优先用
>>>
<< 溢出不报错,但结果完全不可控
Java 整数运算是模 2n 的,<< 超出位宽直接丢高位。例如 int x = 1 << 31 得 Integer.MIN_VALUE,再 << 1 变成 0 —— 不是报错,而是静默错误。
- 编译器不会警告,运行时也不抛异常
- 替代方案:用
Math.multiplyExact()或Math.addExact()等带溢出检查的方法,再配合位移判断是否安全 - 如果输入来自外部(如配置、网络),必须先校验范围,不能假设“只是乘个 2”就安全
JIT 编译器早就会把 * 8 自动转成 << 3,手动写反而干扰可读性
现代 HotSpot JVM 在 C2 编译阶段会对常量乘除做强度削减(strength reduction),i * 64 和 i << 6 生成的机器码通常一模一样。你手写位移,除了让同事多花 3 秒理解,没实际收益。
立即学习“Java免费学习笔记(深入)”;
- 只有在明确被 JIT 排除的场景(如反射调用、未预热的冷路径)才可能有微弱差异
- 更值得优化的是算法复杂度或缓存局部性,而不是这种粒度
- 如果真在性能关键路径(如游戏循环、高频序列化),用 JMH 测,别猜
真正容易被忽略的是:位移操作的优先级比加减还低。a + b << 2 实际等价于 a + (b << 2),不是 (a + b) << 2 —— 不加括号,bug 就藏得特别深。











