Java 运算符
运算符是任何编程语言的骨架,它们赋予了我们执行计算、比较数据以及控制程序流程的能力。在 Java 中,运算符是特殊的符号,用于对一个、两个或三个操作数(变量或值)执行特定操作。扎实掌握运算符是编写高效 Java 代码的关键前提。
本章将全面讲解算术、关系和逻辑运算符,为你提供在程序中处理数据和制定决策的必备工具。
1. 算术运算符 (Arithmetic Operators)
算术运算符用于执行数学计算。Java 提供了一组二元算术运算符(需要两个操作数参与)和一元运算符(只需要一个操作数参与)。
1.1 二元算术运算符
这些运算符使用两个操作数来进行计算。
| 运算符 | 名称 | 描述 | 示例 | 结果 |
|---|---|---|---|---|
+ | 加法 (Addition) | 将两个操作数相加。 | 5 + 3 | 8 |
- | 减法 (Subtraction) | 从第一个操作数中减去第二个操作数。 | 5 - 3 | 2 |
* | 乘法 (Multiplication) | 将两个操作数相乘。 | 5 * 3 | 15 |
/ | 除法 (Division) | 第一个操作数除以第二个操作数。 | 15 / 3 | 5 |
% | 取模/求余 (Modulus) | 返回除法运算后的余数。 | 16 % 3 | 1 |
代码示例:
public class ArithmeticExample {
public static void main(String[] args) {
int a = 10;
int 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
}
}解析: 上面的代码演示了整数操作数下的二元算术运算。特别注意,当两个操作数都是整数时,除法运算符 / 执行的是整数除法,它会直接截断(舍弃)任何小数部分。
1.2 一元算术运算符
这些运算符仅对单一操作数执行操作。
| 运算符 | 名称 | 描述 | 示例 | 结果 |
|---|---|---|---|---|
+ | 正号 (Unary plus) | 将 short, byte, char 提升为 int。对 int 或更大类型无影响。 | +5 | 5 |
- | 负号 (Unary minus) | 对表达式取反;翻转数字的正负号。 | -5 | -5 |
++ | 自增 (Increment) | 将操作数的值增加 1。可作为前缀 (++a) 或后缀 (a++) 使用。 | a++ 或 ++a | a 变成 a+1 |
-- | 自减 (Decrement) | 将操作数的值减少 1。可作为前缀 (--a) 或后缀 (a--) 使用。 | a-- 或 --a | a 变成 a-1 |
代码示例:
public class UnaryExample {
public static void main(String[] args) {
int a = 5;
System.out.println("a 的初始值: " + a); // 输出: 5
System.out.println("正号: " + (+a)); // 输出: 5 (没有变化)
System.out.println("负号: " + (-a)); // 输出: -5
System.out.println("后缀自增 (Post-increment): " + (a++)); // 输出: 5 (先使用 a 的当前值打印,然后再将 a 加 1)
System.out.println("后缀自增后的 a 值: " + a); // 输出: 6
System.out.println("前缀自减 (Pre-decrement): " + (--a)); // 输出: 5 (先将 a 减 1,然后再使用新值打印)
}
}解析: 自增 (++) 和自减 (--) 运算符的行为取决于它们是作为前缀还是后缀使用。
- 前缀 (Prefix)(例如
++a):变量a的值会先增加,然后再参与表达式的计算。 - 后缀 (Postfix)(例如
a++):变量a的值会先参与表达式的计算,然后自身再增加。
1.3 复合赋值运算符
Java 还提供了复合赋值运算符,它们将算术运算和赋值操作合二为一,让代码更简洁。
| 运算符 | 示例 | 等价于 |
|---|---|---|
+= | a += b | a = a + b |
-= | a -= b | a = a - b |
*= | a *= b | a = a * b |
/= | a /= b | a = a / b |
%= | a %= b | a = a % b |
代码示例:
public class CompoundAssignmentExample {
public static void main(String[] args) {
int a = 10;
a += 5; // 等同于 a = a + 5
System.out.println("a += 5: " + a); // 输出: 15
a -= 3; // 等同于 a = a - 3
System.out.println("a -= 3: " + a); // 输出: 12
a *= 2; // 等同于 a = a * 2
System.out.println("a *= 2: " + a); // 输出: 24
a /= 4; // 等同于 a = a / 4
System.out.println("a /= 4: " + a); // 输出: 6
a %= 2; // 等同于 a = a % 2
System.out.println("a %= 2: " + a); // 输出: 0
}
}2. 关系运算符 (Relational Operators)
关系运算符用于比较两个操作数。关系运算的结果永远是一个布尔值 (boolean):true(真) 或 false(假)。
| 运算符 | 名称 | 描述 | 示例 (假设 a=5, b=10) | 结果 |
|---|---|---|---|---|
== | 等于 | 如果两个操作数相等,返回 true,否则返回 false。 | a == b | false |
!= | 不等于 | 如果两个操作数不相等,返回 true,否则返回 false。 | a != b | true |
> | 大于 | 如果第一个操作数大于第二个,返回 true,否则返回 false。 | a > b | false |
< | 小于 | 如果第一个操作数小于第二个,返回 true,否则返回 false。 | a < b | true |
>= | 大于或等于 | 如果第一个操作数大于或等于第二个,返回 true,否则 false。 | a >= b | false |
<= | 小于或等于 | 如果第一个操作数小于或等于第二个,返回 true,否则 false。 | a <= b | true |
代码示例:
public class RelationalExample {
public static void main(String[] args) {
int a = 5;
int b = 10;
System.out.println("a == b: " + (a == b)); // 输出: false
System.out.println("a != b: " + (a != b)); // 输出: true
System.out.println("a > b: " + (a > b)); // 输出: false
System.out.println("a < b: " + (a < b)); // 输出: true
System.out.println("a >= b: " + (a >= b)); // 输出: false
System.out.println("a <= b: " + (a <= b)); // 输出: true
boolean isEqual = (a == 5);
System.out.println("isEqual (a 等于 5 吗): " + isEqual); // 输出: true
}
}解析: 关系运算符在条件判断语句(下一模块会讲到)中被极其频繁地使用,用于根据特定条件控制程序的执行走向。像 a == 5 这样的比较表明,你不仅可以比较两个变量,也可以将变量与具体的字面量(固定值)进行比较。
3. 逻辑运算符 (Logical Operators)
逻辑运算符用于将两个或多个布尔表达式组合起来。逻辑运算的结果同样永远是一个布尔值:true 或 false。
| 运算符 | 名称 | 描述 | 示例 (假设 a=true, b=false) | 结果 |
|---|---|---|---|---|
&& | 逻辑与 (AND) | 只有当两个操作数都为 true 时,才返回 true。具有短路特性。 | a && b | false |
|| | 逻辑或 (OR) | 只要有至少一个操作数为 true,就返回 true。具有短路特性。 | a || b | true |
! | 逻辑非 (NOT) | 反转操作数的布尔值。真变假,假变真。 | !a | false |
& | 按位与 / 逻辑与 | 行为类似 &&,但不具备短路特性,总是执行两边的评估。 | a & b | false |
| | 按位或 / 逻辑或 | 行为类似 ||,但不具备短路特性,总是执行两边的评估。 | a | b | true |
^ | 逻辑异或 (XOR) | 当且仅当两个操作数一个为真,另一个为假时,返回 true。否则返回 false。 | a ^ b | true |
代码示例:
public class LogicalExample {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println("a && b: " + (a && b)); // 输出: false
System.out.println("a || b: " + (a || b)); // 输出: true
System.out.println("!a: " + (!a)); // 输出: false
System.out.println("a & b: " + (a & b)); // 输出: false
System.out.println("a | b: " + (a | b)); // 输出: true
System.out.println("a ^ b: " + (a ^ b)); // 输出: true
}
}深度解析:
- 短路求值 (Short-circuiting):
&&和||运算符具有短路行为。这意味着如果仅通过评估左边的操作数就能确定整个表达式的结果,Java 就不会再去执行/评估右边的操作数。 - 例如在
a && b中,如果a已经是false,那么整个表达式注定是false,此时b根本不会被执行。 - 同理,在
a || b中,如果a已经是true,整个表达式注定是true,b同样被跳过。 - 按位 vs 逻辑:
&和|原本是按位运算符,但也可以用于布尔值。与&&和||最大的区别是,它们没有短路特性,无论左边结果如何,右边的表达式都一定会执行。在日常逻辑判断中,强烈建议使用&&和||。 - 逻辑异或 (XOR):
^只有在两边状态“相异”(一真一假)时才返回true。如果两边都是真,或者都是假,它返回false。
3.1 组合运算符
你可以组合多个运算符来创建更复杂的表达式。可以使用小括号 () 来控制运算的优先级。
代码示例:
public class CombinedOperators {
public static void main(String[] args) {
int age = 25;
boolean isStudent = true;
// 检查某人是否有资格享受折扣(未满18岁 或者 是学生)
boolean eligibleForDiscount = (age < 18) || isStudent;
System.out.println("是否有折扣资格: " + eligibleForDiscount); // 输出: true
// 检查某人是否是成年人 并且 不是学生
boolean isAdultAndNotStudent = (age >= 18) && !isStudent;
System.out.println("是成年人且不是学生: " + isAdultAndNotStudent); // 输出: false
}
}4. 运算符优先级 (Operator Precedence)
运算符优先级决定了在一个复杂的表达式中,各个运算符被执行的先后顺序。优先级高的运算符会先于优先级低的被评估。
以下是我们讲过的运算符的优先级排名(从高到低):
| 优先级 | 运算符 |
|---|---|
| 1 | ++, -- (后缀 Postfix) |
| 2 | ++, -- (前缀 Prefix), + (一元正号), - (一元负号), ! |
| 3 | *, /, % |
| 4 | +, - |
| 5 | ==, !=, >, <, >=, <= |
| 6 | & |
| 7 | ^ |
| 8 | | |
| 9 | && |
| 10 | || |
| 11 | =, +=, -=, *=, /=, %= (赋值类) |
代码示例:
public class OperatorPrecedence {
public static void main(String[] args) {
int a = 5;
int b = 10;
int c = 2;
int result = a + b * c; // 乘法的优先级高于加法
System.out.println("a + b * c: " + result); // 输出: 25 (相当于 5 + (10 * 2))
int result2 = (a + b) * c; // 小括号 () 拥有最高优先级,强制改变运算顺序
System.out.println("(a + b) * c: " + result2); // 输出: 30 (相当于 (5 + 10) * 2)
boolean boolResult = a > b || b < c && a == 5;
System.out.println("不加括号的布尔组合: " + boolResult); //输出: false
/* 执行顺序解析:
1. 先算 && 两边:b < c 为 false (10 < 2)
2. 关系运算 a == 5 为 true (5 == 5)
3. false && true 结果为 false
4. 再算 || 两边:a > b 为 false (5 > 10)
5. 最终:false || false 结果为 false
*/
}
}解析: 牢记运算符优先级非常重要,它能防止程序得出意料之外的结果。当你不确定时,请果断使用小括号 (),这不仅能确保执行顺序绝对正确,还能极大提升代码的“人类可读性”。