Java 运算符
运算符是程序"做计算"的核心:加减乘除、比较大小、逻辑判断、位运算。Java 的运算符和 C/C++ 几乎一样,本章带你完整过一遍,并指出几个新手最容易踩的坑。
1. 算术运算符
public class ArithOp {
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 取余(模)
System.out.println(10.0 / b); // 3.3333...(有一个 double 就按 double 算)
// ⚠️ 整数除以 0 抛异常 ArithmeticException
// System.out.println(10 / 0); // ❌ 运行时报错
// 浮点除以 0 不报错,得到 Infinity 或 NaN
System.out.println(10.0 / 0); // Infinity
System.out.println(0.0 / 0); // NaN
}
}要点:
- 整数除法截断小数:
10 / 3 = 3,不是 3.33。要小数结果,至少一边是浮点:10.0 / 3。 %是取余(模运算):10 % 3 = 1,常用于判断奇偶(n % 2 == 0)。- 整数除以 0 抛异常,浮点除以 0 得到
Infinity或NaN——这是 IEEE 754 标准。
2. 自增自减(i++ 与 ++i)
++ 和 -- 是把变量加/减 1。前置和后置的区别是返回值的时机:
public class IncDec {
public static void main(String[] args) {
int i = 5;
// i++ :先用 i 的值,再 +1(后置)
System.out.println(i++); // 5(打印后 i 变 6)
System.out.println(i); // 6
// ++i :先 +1,再用 i 的值(前置)
System.out.println(++i); // 7(先 +1 再打印)
System.out.println(i); // 7
// 经典面试题:不要在复杂表达式里混用 ++
int a = 5;
int b = a++ + a++ + a++;
// 5 6 7 -> 18,a 最终变 8
System.out.println(b); // 18
System.out.println(a); // 8
}
}i++:先返回值,再加 1(后置)。++i:先加 1,再返回值(前置)。- 单独一行写(
i++;)时,前置后置效果完全一样,平时用i++居多。 - 不要在复杂表达式里混用
++:虽然能算,但可读性极差,同事会想杀你。
3. 关系运算符
关系运算符的结果是 boolean(true/false),用于条件判断:
public class RelOp {
public static void main(String[] args) {
int a = 10, b = 20;
System.out.println(a > b); // false
System.out.println(a < b); // true
System.out.println(a >= 10); // true
System.out.println(a <= 5); // false
System.out.println(a == 10); // true
System.out.println(a != 10); // false
// ⚠️ == 比较引用类型时,比较的是地址,不是内容!
String s1 = new String("hi");
String s2 = new String("hi");
System.out.println(s1 == s2); // false(两个不同对象)
System.out.println(s1.equals(s2)); // true(内容相同)
// 字符串常量池的特殊情况
String s3 = "hi";
String s4 = "hi";
System.out.println(s3 == s4); // true(指向常量池同一对象)
}
}最大的坑:== 比较引用类型时,比较的是地址,不是内容!字符串比较必须用 .equals(),这是新手最容易踩的雷。IDEA 会给 s1 == s2 这种写法报警告,要养成习惯。
4. 逻辑运算符(&&、||、!)
public class LogicOp {
public static void main(String[] args) {
boolean a = true, b = false;
System.out.println(a && b); // false 短路与:左边 false 时右边不执行
System.out.println(a || b); // true 短路或:左边 true 时右边不执行
System.out.println(!a); // false 非
System.out.println(a & b); // false 逻辑与(非短路,几乎不用)
System.out.println(a | b); // true 逻辑或(非短路)
// 短路特性的典型应用
int x = 0;
if (x != 0 && 10 / x > 1) { // 左边 false,右边 10/x 不执行,避免除零
System.out.println("不会进来");
}
// 用短路特性避免空指针
String s = null;
if (s != null && s.length() > 0) {
System.out.println("s 不空");
}
}
}&& 和 || 是短路运算符——左边能确定结果时,右边根本不执行。这是它们和 & / | 最大的区别。短路特性常用于防御性编程:先判空再调用方法,避免 NPE。
5. 位运算符(用得少但要知道)
位运算直接对整数的二进制位操作,效率高但可读性差。日常业务代码用得少,在底层源码(如 HashMap)、性能优化场景常见。
public class BitOp {
public static void main(String[] args) {
int a = 0b1100; // 12
int b = 0b1010; // 10
System.out.println(a & b); // 8 (0b1000) 按位与
System.out.println(a | b); // 14 (0b1110) 按位或
System.out.println(a ^ b); // 6 (0b0110) 按位异或
System.out.println(~a); // -13 按位取反
System.out.println(a << 2); // 48 (12 * 4) 左移 2 位 = 乘 2^2
System.out.println(a >> 1); // 6 (12 / 2) 右移 1 位 = 除 2
System.out.println(-12 >>> 1); // 2147483642 无符号右移(高位补 0)
// 实战:位运算做权限标志(每个 bit 代表一个权限)
int READ = 1, WRITE = 2, EXEC = 4; // 001 010 100
int perm = READ | WRITE; // 011 = 3,有读+写权限
System.out.println((perm & READ) != 0); // true 有读权限
System.out.println((perm & EXEC) != 0); // false 没有 exec 权限
}
}典型用途:
- 权限标志:每个 bit 代表一个权限,用
|组合,&检查。 - 高效乘除 2 的幂:
n << 2等于n * 4,n >> 1等于n / 2(现代编译器会自动优化,不必硬写)。 - 哈希计算:`HashMap` 用位运算混合 hash。
6. 三目运算符
三目运算符是 if-else 的"一行版",适合简单的二选一赋值:
public class Ternary {
public static void main(String[] args) {
int score = 75;
// 三目运算符:条件 ? 真值 : 假值
String result = score >= 60 ? "及格" : "不及格";
System.out.println(result); // 及格
// 可以嵌套,但可读性差,不推荐过度嵌套
String level = score >= 90 ? "优秀" :
score >= 60 ? "及格" : "不及格";
System.out.println(level); // 及格
// 求两数较大值
int a = 10, b = 20;
int max = a > b ? a : b;
System.out.println(max); // 20
}
}建议:简单赋值用三目,复杂逻辑用 if-else。嵌套三目可读性极差,出现两层就该拆开。
7. 赋值与复合赋值
= 是赋值,还有 +=、-=、*=、/=、%=、&=、|= 等复合赋值运算符:
a += 5等价于a = a + 5,但自带强转(对byte/short友好)。s1 += "world"对 String 来说等价于s1 = s1 + "world"(实际编译成 StringBuilder)。
8. instanceof 运算符
用来判断对象是否属于某个类型(含子类),在向下转型前用 instanceof 检查是避免 ClassCastException 的标准做法:
public class InstanceofDemo {
public static void main(String[] args) {
Object s = "Hello";
// instanceof:判断对象是否属于某类型(或其子类)
if (s instanceof String) {
String str = (String) s; // 安全向下转型
System.out.println(str.length()); // 5
}
// Java 16+ 模式匹配,可直接声明变量
if (s instanceof String str) {
System.out.println(str.toUpperCase()); // HELLO
}
// null instanceof 任何类型都是 false
System.out.println(null instanceof String); // false
}
}9. 运算符优先级(从高到低)
实际开发中不需要全记住,常用规则:
- 乘除模 > 加减 > 关系 > 逻辑(&& 高于 ||) > 赋值
- 单目(> ++ -- !) > 双目
- 三目(? :)介于赋值和 || 之间
拿不准时直接加括号,这是最高优先级规则——既不出错,又提升可读性。
小结
这一章你掌握了 Java 的所有运算符:算术、关系、逻辑、位、三目、instanceof。记住三个新手雷区:整数除法截断、字符串 == 用 equals、短路 && 防 NPE。下一篇我们看 Java 流程控制——让程序能做判断、能循环。
← 上一篇 Java 数据类型
下一篇 Java 流程控制 →