Skip to content

第2课:运算符

🎯 学习目标

  • 掌握算术运算符、关系运算符、逻辑运算符
  • 理解位运算符的使用场景
  • 掌握运算符优先级和结合性
  • 理解短路运算和副作用

📖 一、算术运算符

基本算术运算

运算符说明示例结果
+加法5 + 38
-减法5 - 32
*乘法5 * 315
/除法5 / 22(整数除法)
%取余5 % 21
java
int a = 10, b = 3;
System.out.println(a + b);  // 13
System.out.println(a - b);  // 7
System.out.println(a * b);  // 30
System.out.println(a / b);  // 3(整数除法)
System.out.println(a % b);  // 1(余数)

一元运算符

java
int x = 5;
System.out.println(+x);  // 5(正号)
System.out.println(-x);  // -5(负号)

int y = 10;
y++;  // y = y + 1,后置自增
++y;  // y = y + 1,前置自增
y--;  // y = y - 1,后置自减
--y;  // y = y - 1,前置自减

⚠️ 前置与后置的区别

java
int a = 5;
int b = a++;  // b = 5, a = 6(先赋值,后自增)
int c = ++a;  // c = 7, a = 7(先自增,后赋值)

System.out.println("a = " + a);  // 7
System.out.println("b = " + b);  // 5
System.out.println("c = " + c);  // 7

📖 二、关系运算符(比较运算符)

运算符说明示例结果
==等于5 == 3false
!=不等于5 != 3true
>大于5 > 3true
>=大于等于5 >= 5true
<小于5 < 3false
<=小于等于5 <= 5true
java
int a = 10, b = 20;
System.out.println(a == b);  // false
System.out.println(a != b);  // true
System.out.println(a > b);   // false
System.out.println(a < b);   // true

⚠️ 字符串比较陷阱

java
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

System.out.println(s1 == s2);   // true(字符串池)
System.out.println(s1 == s3);   // false(不同对象)
System.out.println(s1.equals(s3)); // true(正确比较内容)

// 关键:== 比较引用,equals() 比较内容

📖 三、逻辑运算符

运算符说明示例结果
&&逻辑与(短路)true && falsefalse
||逻辑或(短路)true || falsetrue
!逻辑非!truefalse
&逻辑与(不短路)true & falsefalse
|逻辑或(不短路)true | falsetrue

短路运算

java
int a = 5, b = 10;

// && 短路:左侧为 false,右侧不执行
if (a > 10 && b++ > 5) {
    System.out.println("条件成立");
}
System.out.println("b = " + b);  // b = 10(b++ 没有执行)

// || 短路:左侧为 true,右侧不执行
if (a < 10 || b++ > 5) {
    System.out.println("条件成立");
}
System.out.println("b = " + b);  // b = 10(b++ 没有执行)

// & 不短路:两侧都执行
if (a > 10 & b++ > 5) {
    System.out.println("条件成立");
}
System.out.println("b = " + b);  // b = 11(b++ 执行了)

💡 最佳实践

  • 通常使用 && 和 ||(短路版本)
  • 性能更好,避免不必要的计算
  • 避免空指针:if (obj != null && obj.method())

📖 四、赋值运算符

运算符说明示例等价于
=赋值a = 5-
+=加后赋值a += 5a = a + 5
-=减后赋值a -= 5a = a - 5
*=乘后赋值a *= 5a = a * 5
/=除后赋值a /= 5a = a / 5
%=取余后赋值a %= 5a = a % 5
java
int x = 10;
x += 5;   // x = 15
x -= 3;   // x = 12
x *= 2;   // x = 24
x /= 4;   // x = 6
x %= 5;   // x = 1

⚠️ 复合赋值的隐式转换

java
byte b = 10;
// b = b + 5;   // ❌ 编译错误(b + 5 是 int)
b += 5;         // ✅ 正确(自动转换)

// += 等价于 b = (byte)(b + 5)

📖 五、三元运算符(条件运算符)

语法条件 ? 值1 : 值2

java
int a = 10, b = 20;
int max = a > b ? a : b;  // max = 20

String result = a % 2 == 0 ? "偶数" : "奇数";  // "偶数"

// 嵌套三元运算符(不推荐,难读)
int score = 85;
String grade = score >= 90 ? "A" : 
               score >= 80 ? "B" : 
               score >= 70 ? "C" : "D";

💡 使用建议

  • 简单条件用三元运算符
  • 复杂条件用 if-else(可读性更好)

📖 六、位运算符

运算符说明示例结果
&按位与5 & 31
|按位或5 | 37
^按位异或5 ^ 36
~按位取反~5-6
<<左移5 << 110
>>右移(算术)5 >> 12
>>>右移(逻辑)-5 >>> 12147483645

位运算详解

java
int a = 5;   // 二进制:0101
int b = 3;   // 二进制:0011

System.out.println(a & b);   // 1    (0001)
System.out.println(a | b);   // 7    (0111)
System.out.println(a ^ b);   // 6    (0110)
System.out.println(~a);      // -6   (取反)

System.out.println(a << 1);  // 10   (左移1位 = 乘以2)
System.out.println(a >> 1);  // 2    (右移1位 = 除以2)

位运算应用场景

1. 乘除2的幂次

java
int x = 16;
int y = x << 2;  // x * 4 = 64(左移2位)
int z = x >> 3;  // x / 8 = 2(右移3位)

2. 判断奇偶

java
int num = 7;
boolean isOdd = (num & 1) == 1;  // 比 num % 2 更快

3. 交换两个数(不用临时变量)

java
int a = 5, b = 10;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("a = " + a + ", b = " + b);  // a = 10, b = 5

4. 位掩码(权限管理)

java
final int READ = 1;    // 0001
final int WRITE = 2;   // 0010
final int EXECUTE = 4; // 0100

int permission = READ | WRITE;  // 0011(读+写权限)
boolean canRead = (permission & READ) != 0;   // true
boolean canExecute = (permission & EXECUTE) != 0;  // false

📖 七、运算符优先级

从高到低

  1. 括号:()
  2. 一元:++ -- ! ~
  3. 算术:* / % > + -
  4. 移位:&lt;&lt; &gt;&gt; &gt;&gt;&gt;
  5. 关系:&lt; &gt; &lt;= &gt;= > == !=
  6. 位运算:& > ^ > |
  7. 逻辑:&& > ||
  8. 三元:? :
  9. 赋值:= += -= *= /= ...

💡 最佳实践

java
// ❌ 难以理解
int result = a + b * c > d && e || f;

// ✅ 使用括号明确优先级
int result = ((a + (b * c)) > d) && e || f;

// ✅ 更好:拆分表达式
int temp = b * c;
int sum = a + temp;
boolean condition = sum > d && e || f;

🆚 Java vs C 对比

特性C 语言Java
逻辑运算0 为 false,非0 为 true只能用 boolean
位运算支持,常用支持,较少用
sizeofsizeof(int)无(类型大小固定)
指针运算支持不支持(无指针)

💡 实用技巧

1. 安全的除法

java
int a = 10, b = 0;
int result = b != 0 ? a / b : 0;  // 避免除零错误

2. 数值交换

java
// 方法1:临时变量(推荐)
int temp = a;
a = b;
b = temp;

// 方法2:加减法
a = a + b;
b = a - b;
a = a - b;

// 方法3:异或(最高效)
a = a ^ b;
b = a ^ b;
a = a ^ b;

3. 绝对值

java
int abs1 = Math.abs(x);           // 标准方法
int abs2 = x < 0 ? -x : x;        // 三元运算符
int abs3 = (x ^ (x >> 31)) - (x >> 31);  // 位运算(最快)

⚠️ 常见陷阱

陷阱1:复杂表达式副作用

java
int a = 1;
int b = a++ + ++a;

这种代码虽然能运行,但可读性很差。生产代码应拆开写。

陷阱2:用 == 比较浮点数

浮点数存在精度误差,应使用误差范围比较。

java
Math.abs(a - b) < 1e-9

陷阱3:忽略短路行为

短路运算右侧可能不执行,不要把必须执行的副作用放在右侧。

陷阱4:位运算优化过早

现代 JVM 会优化简单算术。为了“快”把代码写成难懂的位运算,通常得不偿失。


🧭 表达式可读性原则

写表达式时优先让人看懂。

text
条件超过两个逻辑运算,考虑拆变量。
混合 && 和 || 时加括号。
不要在条件表达式中修改变量。
位运算只在权限、掩码、底层算法中使用。
三元运算只用于简单二选一。

示例:

java
boolean hasPermission = (permission & READ) != 0;
boolean validUser = user != null && user.isActive();

if (hasPermission && validUser) {
    allow();
}

✅ 掌握标准

学完本课后,应能做到:

text
能使用算术、关系、逻辑、赋值、三元和位运算符。
能解释前置自增和后置自增的差异。
能说明 && 和 || 的短路行为。
能用括号明确复杂表达式优先级。
能用位运算表达简单权限掩码。
能识别字符串 ==、浮点 ==、整数除法等陷阱。
能在可读性和技巧之间做正确取舍。

运算符不是为了炫技,而是为了清晰表达计算和判断。复杂表达式应拆成有名字的中间变量。


📝 练习预告

完成 练习/Ex02_Operators.java

  1. 算术运算综合应用
  2. 自增自减陷阱
  3. 短路运算
  4. 位运算实战
  5. 运算符优先级
  6. 综合:计算器程序

🎓 下一步

  • 第3课:控制流 - if、switch、循环