Java 位运算与位移运算:从底层电路到实战技巧,一篇吃透所有核心!
一、引言
你是不是在看 Java 代码时,总对& ^ <<这些符号感到陌生?明明知道它们是位运算和位移运算,却搞不懂背后的逻辑,更不知道怎么用在实际开发里?其实这些运算一点都不 “抽象”—— 它们直接对应 CPU 底层的半导体电路设计,比如按位与就是 “两个高电压才输出高电压”,左移就是二进制数的快速 “放大”。今天这篇笔记,就从底层原理讲到实战应用,把位运算、位移运算的规则、例子和用法全拆透,让你看完不仅能看懂代码,还能用上这些 “高效运算技巧”!
二、位运算(针对二进制的逐位操作)
位运算的核心是对两个数的二进制位逐位进行计算,共 4 种基础运算,每种运算都有明确的底层原理和实用场景(CPU底层都是一些半导体电路,与半导体电路的设计有关)。
1. 按位与(&):“双 1 才为 1”

-
底层原理:对应半导体电路中 “两个输入都是高电压,才输出高电压”;二进制位中,只有两个数的对应位同时为 1,结果位才是 1,其他情况(0&0、0&1、1&0)结果均为 0。
-
实例计算:
00111 & 01011 = 00011(逐位对比:第 1 位 0&0=0,第 2 位 0&1=0,第 3 位 1&0=0,第 4 位 1&1=1,第 5 位 1&1=1,最终结果 00011)。 -
核心应用:精准判断某二进制位的值(“查位”)。
例:已知未知数二进制为0101x001(x 是第 4 位,从右数),若该数与00001000(仅第 4 位为 1)做 & 运算:-
结果为
00001000→ x=1; -
结果为
00000000→ x=0。
-
2. 按位或(|):“双 0 才为 0”

-
底层原理:对应半导体电路中 “只要有一个输入是高电压,就输出高电压”;二进制位中,只有两个数的对应位同时为 0,结果位才是 0,其他情况(0|1、1|0、1|1)结果均为 1。
-
实例计算:
00111 | 01011 = 01111(逐位对比:第 1 位 0|0=0,第 2 位 0|1=1,第 3 位 1|0=1,第 4 位 1|1=1,第 5 位 1|1=1,最终结果 01111)。
3. 按位异或(^):“不同才为 1”

-
底层原理:对应半导体电路中 “两个输入电压不同,才输出高电压”;二进制位中,两个数的对应位不同(一个 0、一个 1) 时,结果位为 1,相同(0&0、1&1)时结果为 0。
-
实例计算:
00111 ^ 01011 = 01100(逐位对比:第 1 位 0^0=0,第 2 位 0^1=1,第 3 位 1^0=1,第 4 位 1^1=0,第 5 位 1^1=0,最终结果 01100)。 -
核心应用:
(1)三数交换(无需临时变量):利用 “异或两次同一个数,结果不变” 的特性。
例:交换int a = 5(二进制0000 0101)和int b = 3(二进制0000 0011):
①a = a ^ b→a = 0000 0101 ^ 0000 0011 = 0000 0110;
②b = a ^ b→b = 0000 0110 ^ 0000 0011 = 0000 0101(此时 b=5,即原 a 的值);
③a = a ^ b→a = 0000 0110 ^ 0000 0101 = 0000 0011(此时 a=3,即原 b 的值)。
(2)记录两个数的不同位:异或结果中 “1” 的位置,就是两个数对应位不同的地方。
例:A=001、B=100,A^B=101,结果中第 1 位和第 3 位为 1,说明 A 和 B 的这两位不同;若已知 A 和结果 C,可通过B = A ^ C反推 B(反之同理)。
4. 按位取反(~):“逐位翻转”

-
底层原理:仅针对单个数字,将其二进制的每一位0 变 1、1 变 0(注意:Java 中整数是有符号的,取反后需结合补码理解,此处先看基础逻辑)。
-
实例计算:对二进制
0011111000取反 → 结果为1100000111。
三、位移运算(二进制数的整体移动)
位移运算本质是让二进制数整体左移或右移,核心是 “快速缩放”,底层基于补码(负数的补码 = 原码取反 + 1)进行计算,分为左移、有符号右移、无符号右移 3 种。
1. 左移(<<):“数据扩大,补 0 填充”
-
核心逻辑:二进制数整体向左移动 n 位,右边空缺的位用0补全;本质是 “数据扩大”,扩大倍数为 “2 的 n 次方”(类比十进制左移 n 位扩大 10 的 n 次方倍)。
-
关键规则:左移 n 位 = 原数 × 2ⁿ(前提是不超出数据类型的范围)。
-
实例计算:
(1)单个数字左移:0000 0001(十进制 1)<< 3 →0000 1000(十进制 8),即 1×2³=8;
(2)替代乘法运算(更高效):-
4×8 = 4×2³→ 4 的二进制0000 0100左移 3 位 →0010 0000(十进制 32); -
4×9 = 4×(8+1) = 4×2³ + 4×2⁰→ 4 左移 3 位(0010 0000) + 4 左移 0 位(0000 0100) → 结果0010 0100(十进制 36); -
4×218 = 4×(128+64+16+8+2) = 4×(2⁷+2⁶+2⁴+2³+2¹)→ 4 左移 7 位 + 左移 6 位 + 左移 4 位 + 左移 3 位 + 左移 1 位,最终结果为4×218=872。
-
2. 有符号右移(>>):“数据变小,符号位补位”
-
核心逻辑:二进制数整体向右移动 n 位,左边空缺的位用原数的符号位补全(正数符号位为 0,负数为 1);本质是 “数据缩小”,缩小倍数为 “2 的 n 次方”(正数直接缩小,负数需结合补码)。
-
实例计算(以 int 类型 8 位简化表示,实际为 32 位):
(1)正数右移:00001000(十进制 8)>> 2 → 整体右移 2 位,左边补 0 →00000010(十进制 2),即 8÷2²=2;
(2)负数右移:11001000(假设为某负数的补码)>> 2 → 整体右移 2 位,左边补 1(符号位为 1) →11110010;
(3)实际代码验证:-
System.out.println(-8);→ 输出 - 8(原码10000000 00000000 00000000 00001000); -
System.out.println(-8 >> 2);→ 先算 - 8 的补码11111111 11111111 11111111 11111000,右移 2 位补 1 → 补码11111111 11111111 11111111 11111110,转原码后为 - 2,故输出 - 2。
-
3. 无符号右移(>>>):“数据变小,全 0 补位”
-
核心逻辑:二进制数整体向右移动 n 位,左边空缺的位全部用 0 补全(不考虑符号位,即把负数当作正数的二进制来处理),结果始终为非负数。
-
实例计算(以 int 类型 32 位完整表示):
(1)System.out.println(-8);→ 输出 - 8(原码10000000 00000000 00000000 00001000);
(2)System.out.println(-8 >>> 2);→ 先算 - 8 的补码11111111 11111111 11111111 11111000,无符号右移 2 位,左边补 0 → 结果00111111 11111111 11111111 11111110,转十进制为 1073741822,故输出 1073741822。
四、核心总结:位运算与位移运算的关键区别与应用场景
| 运算类型 | 核心操作 | 关键特性 | 典型应用 | |
|---|---|---|---|---|
| 位运算 | (&、^、~) | 二进制逐位计算 | 操作单个二进制位,可精准控制位值 |
查位、 三数交换、 记录不同位 |
| 左移(<<) | 整体左移,补 0 | 快速扩大(×2ⁿ),效率高于乘法 |
替代整数乘法 (如 x×8=x<<3) |
|
| 有符号右移(>>) | 整体右移,补符号位 | 快速缩小(÷2ⁿ),保留符号 |
正数 / 负数的整数除法 (如 8>>2=2) |
|
| 无符号右移(>>>) | 整体右移,补 0 | 快速缩小,结果非负 | 仅处理非负数或需忽略符号的场景 |
五、结语
从按位与的 “查位”、异或的 “三数交换”,到左移替代乘法、无符号右移的特殊处理,我们终于把 Java 里的位运算和位移运算讲明白了。这些运算看似 “小众”,却是理解底层逻辑、写出高效代码的关键 —— 比如用x<<3替代x*8,执行速度会快很多;用异或交换变量,还能省掉临时变量。把这篇笔记收起来,下次遇到位运算相关的代码,你就能一眼看穿逻辑;需要优化运算效率时,这些技巧也能帮上大忙。关注我,后续还会拆解更多 Java 底层知识,让复杂的原理变得 “一看就懂”~
更多推荐



所有评论(0)