左移不用于取整,它等价于乘以2ⁿ;向下取整适用于右移或整数除法,而非左移。

左移
是的,但只在不溢出的前提下成立。比如 5 得到 20,确实等于 <code>5 * 4;但 Integer.MAX_VALUE 结果是 -2,显然不是乘法意义上的“翻倍”——它只是二进制位向左平移、高位被截断、符号位翻转后的结果。
- 正数左移 n 位 ≈ 乘以
Math.pow(2, n),前提是结果没超出int(32 位)或long(64 位)范围 - 负数也适用该规则,因为 Java 中整数用补码表示,左移时高位丢弃、低位补 0,数学上仍满足“×2ⁿ”,比如
-3 是 -6 - 一旦溢出(如
1073741824 ,即 <code>0x40000000 ),结果会绕回成负数,此时不能再当乘法看
为什么 -123 >> 2 等于 -31,而不是 -30.75?
因为带符号右移 >> 对负数做的是“向下取整的除法”,本质是补码右移 + 符号位扩展。这不是四舍五入,也不是截断小数,而是按二进制补码逻辑严格推导出来的结果。
-
-123的 32 位补码是11111111 11111111 11111111 10000101 - 右移 2 位后,高位补 1(保持负号),得到
11111111 11111111 11111111 11100001,即 -31 - 别试图用
(int) (-123 / 4.0)验证——Java 的>>不依赖浮点除法,它直接操作位,所以结果恒为向下取整(floor division)
什么时候该用
现代 JVM 编译器基本都会把 x * 2^n 自动优化成 x ,所以手动写左移**不是为了性能**,而是为了表达意图或配合位操作。
- 设置标志位:
flags |= (1 比 <code>flags |= 8更清晰地表明“开第 4 位” - 构造掩码:
mask = (1 快速生成低 n 位全 1 的数(如 <code>n=3 → 0b111) - 数组索引偏移:某些底层框架(如 Netty 的 ByteBuf)用
index 表示 int 数组下标,强调“每个元素占 4 字节” - 别为“看起来快”硬套左移,比如
price * 10写成price 反而难读且无收益
容易被忽略的类型陷阱
移位运算符对 byte、short、char 会先自动提升为 int 再运算,结果也是 int,这常导致意料之外的符号扩展或高位污染。
立即学习“Java免费学习笔记(深入)”;
byte b = -1; int r = b → <code>r是-4,但你以为只动了 8 位?其实b先被转成int的 -1(0xFFFFFFFF),再左移- 想安全操作低位,得显式截断:
byte result = (byte)(b char c = '\uFF00'; c 会变成一个超大正数(65280),因为 <code>char是无符号 16 位,提升后仍是正的int
补码、溢出、类型提升——这三个点串起来,才是理解 和 <code>>> 数学意义的真正钥匙。漏掉任何一个,都可能在边界 case 上栽跟头。










