主题
Chapter 03 · 运算符与表达式
学会用 Java 算账、比较、判断 — 编程的"加减乘除"全在这一章。
🎯 本章目标
- 掌握 Java 的 算术、赋值、比较、逻辑、位、三元 运算符
- 理解 运算符优先级 与 结合性
- 写得出 短路求值、避开整数除法、自增自减坑
- 知道 位运算 在工程中的实际用途
1. 运算符总览
把 Java 的运算符按"用途"分成 6 大类,记忆的时候按类来记,比一个个背强多了。
2. 算术运算符(最熟悉的一类)
| 运算符 | 含义 | 例子 | 结果 |
|---|---|---|---|
+ | 加 / 字符串拼接 | 1 + 2 "a"+"b" | 3 "ab" |
- | 减 | 5 - 3 | 2 |
* | 乘 | 4 * 2 | 8 |
/ | 除 | 7 / 2 | 3(整数除法!) |
% | 取余 / 取模 | 7 % 2 | 1 |
++ | 自增 1 | i++ 或 ++i | 见下方 |
-- | 自减 1 | i-- 或 --i | 见下方 |
整数除法的坑
java
int a = 7;
int b = 2;
System.out.println(a / b); // 3,不是 3.5
System.out.println(a / 2.0); // 3.5,只要有一个是浮点就 OK
System.out.println((double) a / b); // 3.5💡 生活类比:分糖果。7 颗糖分给 2 个小朋友,每人 3 颗(
7/2=3),剩 1 颗放回(7%2=1)。这就是整除和取模。
自增自减:i++ vs ++i
java
int i = 5;
int a = i++; // 先赋值再自增:a = 5,i = 6
int b = ++i; // 先自增再赋值:i = 7,b = 7口诀:++ 在前先算后用,++ 在后先用后算。
🚨 面试坑题:
javaint x = 1; x = x++; // 猜猜 x 是几?答:1!因为
x++先取值 1 备用,再让 x 自增成 2,最后把"备用的 1"赋值回 x。
3. 赋值运算符
| 运算符 | 等价形式 |
|---|---|
= | 赋值 |
+= | a = a + b |
-= | a = a - b |
*= | a = a * b |
/= | a = a / b |
%= | a = a % b |
🤓 隐藏特性:复合赋值
+=等内置了强制类型转换:javashort s = 10; s = s + 1; // ❌ 编译错误(int 不能直接给 short) s += 1; // ✅ 编译通过!等价于 s = (short)(s + 1)
4. 比较运算符(结果是 boolean)
| 运算符 | 含义 | 例子 |
|---|---|---|
== | 等于(基本类型比值,引用类型比地址) | a == b |
!= | 不等于 | a != b |
> < | 大于 / 小于 | 5 > 3 |
>= <= | 大于等于 / 小于等于 | a >= 18 |
字符串千万别用 ==
java
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false ❌
System.out.println(a.equals(b)); // true ✅口诀:比内容用 equals,比身份用 ==。
5. 逻辑运算符(连接 boolean 表达式)
| 运算符 | 含义 | 短路 | 例子 |
|---|---|---|---|
&& | 与(and) | ✅ | age >= 18 && age <= 60 |
|| | 或(or) | ✅ | isVip || points > 1000 |
! | 非(not) | - | !isFinished |
& | 不短路与 | ❌ | 两边都会执行 |
| | 不短路或 | ❌ | 两边都会执行 |
短路求值是什么?
java
int x = 0;
if (x != 0 && 10 / x > 1) { // x != 0 为 false,&& 后面直接跳过
// ...
}
// 用 & 就会爆炸:if (x != 0 & 10/x > 1) → ArithmeticException💡 生活类比:去吃饭看 A 大众点评 4.5 分以上 && B 评论数大于 100。如果 A 已经不满足,B 看都不用看,直接走人。这就是短路。
6. 位运算符(高阶选修,但面试常考)
| 运算符 | 含义 | 例子 | 二进制 |
|---|---|---|---|
& | 按位与 | 5 & 3 = 1 | 101 & 011 = 001 |
| | 按位或 | 5 | 3 = 7 | 101 | 011 = 111 |
^ | 按位异或(不同为 1) | 5 ^ 3 = 6 | 101 ^ 011 = 110 |
~ | 按位取反 | ~5 = -6 | 二补码取反 |
<< | 左移 | 5 << 1 = 10 | 等于 ×2 |
>> | 右移(带符号) | 5 >> 1 = 2 | 等于 ÷2 |
>>> | 无符号右移 | 高位补 0 | 用于 hash |
工程中真实用途
- 快速 ×2 / ÷2:
x << 1比x * 2略快(极少需要这么抠) - 判断奇偶:
(n & 1) == 0判断偶数 - 权限位操作:用一个 int 存多个开关
- HashMap 计算下标:
hash & (length - 1) - 交换两数(不用临时变量):
a ^= b; b ^= a; a ^= b;
java
// 例:用一个 int 存四个权限
final int READ = 1; // 0001
final int WRITE = 2; // 0010
final int EXECUTE = 4; // 0100
final int DELETE = 8; // 1000
int permission = READ | WRITE; // 既能读又能写
boolean canRead = (permission & READ) != 0;
boolean canDelete = (permission & DELETE) != 0; // false7. 三元运算符(条件运算符)
简洁版 if-else,只能写一行:
java
int score = 85;
String grade = score >= 60 ? "及格" : "不及格";
// 等价于
String g;
if (score >= 60) g = "及格";
else g = "不及格";可以嵌套,但不要超过 2 层(不然没人看得懂):
java
String level = score >= 90 ? "优"
: score >= 80 ? "良"
: score >= 60 ? "中"
: "差";8. 运算符优先级(不用全记,关键时加括号)
记忆技巧:高层级 → 低层级:
- 后缀(
x++x--) - 一元(
!~++x) - 算术(
* /% > + -) - 移位(
<< >> >>>) - 比较(
< <= > >= instanceof== !=) - 位运算(
& > ^ > |) - 逻辑(
&& > ||) - 三元(
? :) - 赋值(
= += -= ...)
💡 实战建议:除了
*+-/这种基础的,其他全部 加括号 让代码意图明确,省得你和审代码的同事吵架。
9. 实战练习
| 文件 | 内容 |
|---|---|
OperatorDemo.java | 各类运算符演示 |
AutoIncrementPitfall.java | i++ vs ++i 经典面试题 |
BitOperationDemo.java | 位运算实际应用 |
PermissionSystem.java | 用位运算实现权限系统 |
10. 浏览器演示
打开 demo.html:
- 运算符在线计算器
- 短路求值动画演示
- 二进制位运算可视化
11. 面试可能会问什么?
Q1: a == b 和 a.equals(b) 有什么区别?
==比较 值(基本类型) 或 引用地址(引用类型).equals()默认与==等价(Object 类的实现),但 String、Integer 等类 重写 了 equals,比较的是 内容
Q2: i++ 和 ++i 的区别?
i++:先取值,后自增++i:先自增,再取值
java
int i = 5;
int a = i++; // a=5, i=6
int b = ++i; // i=7, b=7Q3: 解释 int x = 1; x = x++; 的结果
答:x 还是 1。
- 等价于
int tmp = x; x = x + 1; x = tmp; - 最终 x 被赋值回 1。
Q4: && 和 & 有什么区别?
| 对比 | && | & |
|---|---|---|
| 短路 | 是 | 否 |
| 类型 | 仅 boolean | boolean 或位运算 |
| 性能 | 短路时更快 | 始终算两侧 |
| 安全 | 防 NPE/除零 | 可能触发异常 |
Q5: 0.1 + 0.2 == 0.3 是 true 吗?
答:false。浮点二进制表示问题。详见 Chapter 02。
Q6: 怎么不用临时变量交换两个 int?
java
int a = 3, b = 5;
a = a ^ b;
b = a ^ b; // b = (a^b)^b = a
a = a ^ b; // a = (a^b)^a = b
// 现在 a=5, b=3⚠️ 实际工程不推荐这样写,可读性差,编译器优化后正常写法一样快。
Q7: 为什么 HashMap 用 hash & (length-1) 而不是 hash % length?
答:当 length 是 2 的幂时,hash & (length-1) 等价于 hash % length,但 位运算比取模快得多。这是 HashMap 强制 length 必须是 2 的幂的原因之一。
Q8: >> 和 >>> 的区别?
>>算术右移:高位补符号位(正数补 0,负数补 1)>>>逻辑右移:高位永远补 0
java
int n = -8; // 二进制: 1111...1000
System.out.println(n >> 2); // -2 (高位补 1)
System.out.println(n >>> 2); // 1073741822 (高位补 0)🎁 本章小结
✅ 6 类运算符:算术、赋值、比较、逻辑、位、三元
✅ 字符串比较只能用 .equals()
✅ && || 短路求值,能避免 NPE 和除零
✅ 位运算用于权限、HashMap、性能场景
✅ 实在记不住优先级,加括号最稳🔗 导航
- ⬅️ 上一章:Chapter 02 · 变量与数据类型
- ➡️ 下一章:Chapter 04 · 流程控制