重阳,来,我们把 Java 操作符 这个“最容易被低估却最常坑人”的基础彻底吃透。
重点覆盖:分类 + 优先级差异 + 位运算核心前置(进制/原码反码补码) + Java vs C 关键对比。
目标:看完能手算任意表达式 + 面试/刷题/底层代码不再慌。
1. Java 操作符完整分类(2026 年视角,JDK 21+ 无大变化)
| 优先级组(从高到低) | 操作符 | 结合性 | 说明 / 常见坑点 |
|---|---|---|---|
| 1 | () [] . new :: | 左→右 | 最高,括号最强 |
| 2 | expr++ expr– | 左→右 | 后置自增/自减 |
| 3 | ++expr –expr + – ! ~ (type) | 右→左 | 前置 + 取负 + 逻辑非 + 按位取反 + 强制转换 |
| 4 | * / % | 左→右 | 乘除取模 |
| 5 | + – | 左→右 | 加减(+ 还能字符串拼接) |
| 6 | << >> >>> | 左→右 | 位移(>>> 是 Java 独有) |
| 7 | < <= > >= instanceof | 左→右 | 关系 + 类型判断 |
| 8 | == != | 左→右 | 相等(对象比较引用,值类型比较值) |
| 9 | & | 左→右 | 按位与(也可用于 boolean 逻辑与) |
| 10 | ^ | 左→右 | 按位异或 |
| 11 | 左→右 | ||
| 12 | && | 左→右 | 短路逻辑与 |
| 13 | |||
| 14 | ? : | 右→左 | 三元运算符 |
| 15 | = += -= *= /= %= &= ^= | = <<= >>= >>>= | 右→左 |
最容易错的优先级记忆口诀(前6个最重要):
“单目算术位移,乘除加减,位移关系等,位与异或或,逻辑短路,三目赋值”
常见陷阱:
a & b == c→ 先算b == c,再a & 结果(因为 == 优先级高于 &)-5 >> 1vs-5 >>> 1(后面详解)i = i++ + ++i;(未定义行为,千万别写!)
2. 位运算前置:原码、反码、补码(必懂!)
Java 中所有整数(byte/short/int/long)一律用补码表示。
| 概念 | 正数示例 (以 8 bit 为例) | 负数示例 (-5, 8 bit) | 特点 / 记忆法 |
|---|---|---|---|
| 原码 | +5 → 00000101 | -5 → 10000101 | 最高位是符号位(0正1负),其余是绝对值 |
| 反码 | +5 → 00000101 | -5 → 11111010(符号位不变,其余取反) | 正数反码=原码,负数符号位不变其余取反 |
| 补码 | +5 → 00000101 | -5 → 11111011(反码+1) | 计算机实际存储的就是补码 |
关键性质(背下来!):
- 正数的原码 = 反码 = 补码
- 负数的补码 = 反码 + 1
- 补码的补码 = 原码(绕一圈回来)
- ~x(按位取反)其实是 -x-1(补码世界里的数学性质)
- 例:~5 = -6(因为 00000101 → 11111010 → 补码转十进制 = -6)
为什么用补码?
加减法统一(不用区分正负数电路不同)
0 有唯一表示(不像原码有 +0 和 -0)
3. Java 位运算符详解 + 与 C 的核心差异
| 操作符 | 含义 | Java 行为(int 示例) | C/C++ 对应行为对比 | 关键差异点 |
|---|---|---|---|---|
| & | 按位与 | 5 & 3 = 1 (0101 & 0011 = 0001) | 完全相同(纯位运算) | 无 |
| 按位或 | 5 | 3 = 7 | ||
| ^ | 按位异或 | 5 ^ 3 = 6 | 相同 | 无 |
| ~ | 按位取反(一元) | ~5 = -6 | 相同(但 C 中 int 可能是 32/64 bit 实现依赖) | 无大差异 |
| << | 算术左移(带符号,无差异) | 5 << 2 = 20 -5 << 2 = -20 | 相同(左移不影响符号位) | 无 |
| >> | 算术右移(带符号) | 5 >> 2 = 1 -5 >> 2 = -2(符号扩展) | C 中 >> 对 signed int 是实现定义(多数编译器算术右移) | Java 强制算术右移,C 可能逻辑右移(老编译器) |
| >>> | 逻辑右移(无符号) | 5 >>> 2 = 1 -5 >>> 2 = 1073741822 | C/C++ 没有 >>>!右移 signed 通常算术,unsigned 才逻辑 | 最大差异!Java 独有,解决负数右移问题 |
负数 >>> 演示(非常重要!)
int a = -5; // 二进制:1111 1111 1111 1111 1111 1111 1111 1011
System.out.println(a >> 2); // -2 (1111 1111 ... 1110 符号扩展)
System.out.println(a >>> 2); // 1073741822 (0011 1111 ... 1110 最高位补0)
C 语言里想实现无符号右移,只能把变量转为 unsigned int 或 unsigned long。
4. 常见位运算经典用法(刷题/面试必备)
| 用途 | 表达式示例 | 说明 |
|---|---|---|
| 判断奇偶 | (n & 1) == 1 | 最快判断奇数 |
| 取绝对值(不使用 Math) | (n ^ (n >> 31)) – (n >> 31) | 经典位运算取 abs(仅 int/long 有效) |
| 交换两数(不使用临时变量) | a ^= b; b ^= a; a ^= b; | 经典面试题 |
| 求 2 的幂次方 | n & (n-1) == 0 && n > 0 | 判断是否 2 的幂 |
| 统计二进制 1 的个数 | n &= (n-1) 循环直到 n==0 | Brian Kernighan 算法(最快) |
| 取低 n 位 | x & ((1 << n) – 1) | 掩码取低 n 位 |
| 设置第 k 位为 1 | x | = (1 << k) |
| 设置第 k 位为 0 | x &= ~(1 << k) | — |
| 翻转第 k 位 | x ^= (1 << k) | — |
5. 快速自测题(建议现在算一算)
- -8 >> 3 的结果是?(十进制)
- -8 >>> 3 的结果是?(注意 int 32 位)
- 表达式: 8 + (-3) & 7 的值?(优先级陷阱)
- ~0 的值是多少?
- 如何用位运算实现 ×8(不写 *)?
答案稍后可以问我,或者自己 System.out.println() 验证。
重阳,位运算 + 补码 + 优先级这三块吃透后,后面集合、IO、多线程里的位标志、哈希计算、布隆过滤器、权限校验等都会轻松很多。
现在你最想:
- 看更多经典位运算面试题?
- 手写几个位运算算法?
- 继续下一节(比如自动类型转换 & 强制转换的坑)?
- 还是有具体代码想让我帮你分析为什么结果是这样?
随时说,我们继续冲~