05 - 运算符:算术、逻辑、位运算、三元
05 - 运算符:算术、逻辑、位运算、三元
算术运算符
| 运算符 | 名称 | 示例 | 结果 |
|---|
+ | 加 | 10 + 3 | 13 |
- | 减 | 10 - 3 | 7 |
* | 乘 | 10 * 3 | 30 |
/ | 除 | 10 / 3 | 3(整数除法截断) |
% | 取模 | 10 % 3 | 1 |
++ | 自增 | i++ / ++i | i = i + 1 |
-- | 自减 | i-- / --i | i = i - 1 |
public class ArithmeticDemo {
public static void main(String[] args) {
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
// 浮点除法
double da = 10.0, db = 3.0;
System.out.println("浮点除法: " + (da / db)); // 3.3333...
// 自增前缀 vs 后缀
int x = 5;
int y = x++; // y = 5, x = 6(先赋值后自增)
int z = ++x; // z = 7, x = 7(先自增后赋值)
System.out.println("x=" + x + ", y=" + y + ", z=" + z);
// 整数溢出
int max = Integer.MAX_VALUE; // 2147483647
System.out.println("溢出: " + (max + 1)); // -2147483648
// 除以零
// int div = 10 / 0; // ❌ ArithmeticException
double d = 10.0 / 0.0; // ✅ Infinity(不会抛异常)
System.out.println("浮点除零: " + d); // Infinity
}
}
赋值运算符
| 运算符 | 等价于 | 示例 |
|---|
= | - | a = 10 |
+= | a = a + b | a += 5 |
-= | a = a - b | a -= 3 |
*= | a = a * b | a *= 2 |
/= | a = a / b | a /= 4 |
%= | a = a % b | a %= 3 |
&= | a = a & b | a &= 0xFF |
|= | a = a | b | a |= 0x01 |
^= | a = a ^ b | a ^= mask |
<<= | a = a << n | a <<= 2 |
>>= | a = a >> n | a >>= 1 |
⚠️ 复合赋值运算符会自动进行类型转换:byte b = 10; b += 5; 等价于 b = (byte)(b + 5);
比较运算符
| 运算符 | 含义 | 示例 |
|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
instanceof | 类型检查 | obj instanceof String |
public class ComparisonDemo {
public static void main(String[] args) {
// 基本类型:比较值
int a = 10, b = 20;
System.out.println(a == b); // false
System.out.println(a != b); // true
// 包装类陷阱
Integer x = 128, y = 128;
System.out.println(x == y); // false!(比较引用)
System.out.println(x.equals(y)); // true(比较值)
// 字符串比较
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(不同对象)
System.out.println(s1.equals(s2)); // true(值相等)
System.out.println("hello" == "hello"); // true(字面量共享)
// instanceof(JDK 16+ 模式匹配)
Object obj = "Hello";
if (obj instanceof String s) {
System.out.println("长度: " + s.length()); // 无需强转
}
}
}
逻辑运算符
| 运算符 | 含义 | 特点 |
|---|
&& | 短路与 | 左侧为 false 时,右侧不执行 |
|| | 短路或 | 左侧为 true 时,右侧不执行 |
! | 逻辑非 | 取反 |
& | 逻辑与 | 两侧都执行 |
| | 逻辑或 | 两侧都执行 |
^ | 逻辑异或 | 不同为 true |
public class LogicDemo {
public static void main(String[] args) {
// 短路求值
int x = 0;
// if (x != 0 && 10 / x > 1) { ... } // 安全,短路
// if (x != 0 & 10 / x > 1) { ... } // ❌ ArithmeticException!
// 三元运算符
int score = 85;
String grade = score >= 60 ? "及格" : "不及格";
System.out.println(grade); // 及格
// 嵌套三元(不推荐太深)
String level = score >= 90 ? "优秀"
: score >= 80 ? "良好"
: score >= 60 ? "及格"
: "不及格";
System.out.println(level); // 良好
}
}
位运算符
| 运算符 | 名称 | 示例 | 说明 |
|---|
& | 按位与 | 0b1100 & 0b1010 = 0b1000 | 都为 1 才为 1 |
| | 按位或 | 0b1100 | 0b1010 = 0b1110 | 有 1 就为 1 |
^ | 按位异或 | 0b1100 ^ 0b1010 = 0b0110 | 不同为 1 |
~ | 按位取反 | ~0b1100 = ...0011 | 0 变 1,1 变 0 |
<< | 左移 | 1 << 3 = 8 | 左移 n 位 = ×2ⁿ |
>> | 右移(带符号) | -8 >> 2 = -2 | 高位补符号位 |
>>> | 无符号右移 | -1 >>> 28 | 高位补 0 |
public class BitwiseDemo {
public static void main(String[] args) {
int a = 0b11001010; // 202
int b = 0b10101100; // 172
System.out.println("a & b = " + Integer.toBinaryString(a & b)); // 10001000
System.out.println("a | b = " + Integer.toBinaryString(a | b)); // 11101110
System.out.println("a ^ b = " + Integer.toBinaryString(a ^ b)); // 01100110
System.out.println("~a = " + Integer.toBinaryString(~a));
// 位移运算
System.out.println("1 << 4 = " + (1 << 4)); // 16
System.out.println("16 >> 2 = " + (16 >> 2)); // 4
// 实际应用:权限标志
final int READ = 0b001; // 1
final int WRITE = 0b010; // 2
final int EXECUTE = 0b100; // 4
int permission = READ | WRITE; // 赋予读写权限
System.out.println("有读权限: " + ((permission & READ) != 0)); // true
System.out.println("有执行权限: " + ((permission & EXECUTE) != 0)); // false
// 切换权限
permission ^= EXECUTE; // 添加执行权限
permission ^= READ; // 移除读权限
System.out.println("最终权限: " + Integer.toBinaryString(permission)); // 110
}
}
位运算实用技巧
public class BitTricks {
public static void main(String[] args) {
// 判断奇偶(比 % 2 快)
int n = 7;
System.out.println((n & 1) == 0 ? "偶数" : "奇数");
// 乘除 2 的幂
System.out.println(5 << 1); // 10(×2)
System.out.println(5 << 3); // 40(×8)
System.out.println(40 >> 3); // 5(÷8)
// 不用临时变量交换两个数
int x = 3, y = 7;
x ^= y; y ^= x; x ^= y;
System.out.println("x=" + x + ", y=" + y); // x=7, y=3
// 求绝对值(不考虑溢出)
int val = -42;
int abs = (val ^ (val >> 31)) - (val >> 31);
System.out.println("绝对值: " + abs); // 42
}
}
运算符优先级
| 优先级 | 运算符 | 结合性 |
|---|
| 1 | () [] . | 左 → 右 |
| 2 | ! ~ ++ -- +(正) -(负) | 右 → 左 |
| 3 | * / % | 左 → 右 |
| 4 | + - | 左 → 右 |
| 5 | << >> >>> | 左 → 右 |
| 6 | < <= > >= instanceof | 左 → 右 |
| 7 | == != | 左 → 右 |
| 8 | & | 左 → 右 |
| 9 | ^ | 左 → 右 |
| 10 | | | 左 → 右 |
| 11 | && | 左 → 右 |
| 12 | || | 左 → 右 |
| 13 | ? : | 右 → 左 |
| 14 | = += -= 等 | 右 → 左 |
💡 记忆口诀:单目 > 算术 > 移位 > 关系 > 位运算 > 逻辑 > 三元 > 赋值。拿不准就加括号!
⚠️ 注意事项
- 整数溢出不抛异常 — Java 整数溢出会默默回绕,使用
Math.addExact() 等方法可检测溢出。 - 浮点数不能用
== 比较 — 使用 Math.abs(a - b) < 1e-9 或 Double.compare()。 >>> 是 Java 特有的 — 其他语言可能没有无符号右移操作符。- 字符串拼接使用
+ — 编译器会优化为 StringBuilder,但循环中应手动使用 StringBuilder。
💡 技巧
检查 2 的幂:
boolean isPowerOfTwo = (n & (n - 1)) == 0 && n > 0;
位计数:
int bitCount = Integer.bitCount(0b10101010); // 4
数字中 1 的个数(Brian Kernighan 算法):
int count = 0;
int n = 0b10101010;
while (n != 0) { n &= (n - 1); count++; }
🏢 业务场景
- 权限系统: 使用位运算实现 RBAC 权限管理,每个 bit 代表一种权限。
- 分布式 ID: Snowflake 算法使用位移运算组合时间戳、机器 ID、序列号。
- 网络编程: 子网掩码计算大量使用位运算。
📖 扩展阅读