运算符 | JavaSE
运算符
一、学习目标
完成本章后,你应该能够:
- 能够理解运算符(Operator)与表达式(Expression)的基本关系。
- 能够熟练使用算术运算符,并正确分析整数除法、取余运算和字符串拼接。
- 能够区分前置自增、自减与后置自增、自减。
- 能够正确使用基本赋值运算符和复合赋值运算符。
- 能够使用关系运算符和逻辑运算符构造布尔条件。
- 能够解释
&&、||的短路求值机制。 - 能够正确使用三元运算符处理简单二选一逻辑。
- 能够根据运算符优先级和结合方向分析表达式,并知道什么时候应该主动使用括号提高代码可读性。
二、核心知识
2.1 什么是运算符
运算符(Operator)可以理解为:
对一个或多个数据执行某种运算的特殊符号。
例如:
int result = 10 + 20;
其中:
10
20
是操作数(Operand)。
+
是运算符。
而:
10 + 20
整体叫做表达式(Expression)。
表达式计算完成后会产生一个结果:
30
Java 中常见运算符包括:
| 类型 | 常见运算符 |
| ---------- | ------------------ |
| 算术运算符 | + - * / % |
| 自增自减 | ++ -- |
| 赋值运算符 | = += -= *= /= %= |
| 关系运算符 | > < >= <= == != |
| 逻辑运算符 | `& |
| 条件运算符 | ? : |
这一章的核心,不只是记住符号,而是掌握:
运算符作用
+
操作数类型
+
运算顺序
+
表达式结果类型
2.2 算术运算符
Java 中最基本的算术运算符:
| 运算符 | 含义 |
| ------ | ---- |
| + | 加 |
| - | 减 |
| * | 乘 |
| / | 除 |
| % | 取余 |
例如:
int a = 10;
int b = 3;
System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b);
System.out.println(a % b);
分别表示:
10 + 3
10 - 3
10 × 3
10 ÷ 3
10 除以 3 的余数
2.3 整数除法
这是 Java 初学阶段非常重要的规则。
System.out.println(5 / 2);
结果不是:
2.5
而是:
2
原因在于:
int / int
执行的是整数除法。
两个操作数都是 int:
5
2
结果类型仍然是整数类型,因此小数部分不会被保留。
如果希望得到:
2.5
至少需要让一个操作数进入浮点运算。
例如:
System.out.println(5.0 / 2);
或者:
System.out.println((double) 5 / 2);
都可以得到:
2.5
所以不要只盯着:
数学结果应该是什么
还必须考虑:
Java 当前按照什么数据类型执行运算
2.4 % 取余运算符
% 表示余数运算。
例如:
System.out.println(10 % 3);
得到:
1
因为:
10 ÷ 3 = 3 …… 1
取余运算在程序中非常常见。
例如判断奇偶数:
int number = 10;
boolean even = number % 2 == 0;
System.out.println(even);
还可以用于:
周期性处理
数字拆分
循环轮转
奇偶判断
时间换算
下标循环
例如:
int number = 123;
int ones = number % 10;
就可以得到个位数字。
2.5 + 还可以进行字符串拼接
Java 中:
+
并不永远代表数学加法。
当 + 的操作数中存在 String 时,它可以用于字符串拼接。
例如:
String name = "星雨";
int age = 22;
System.out.println(name + age);
得到:
星雨22
这里:
+
不是把字符串和整数做数学加法,而是把数据转换成字符串形式后连接起来。
2.6 连续 + 为什么容易出错
观察:
int a = 5;
System.out.println("abc" + a);
System.out.println(a + 5);
System.out.println("itheima" + a + 'a');
System.out.println(a + 'a' + "itheima");
理解这种代码的关键是:
+按照从左到右进行结合。
例如:
a + 'a' + "itheima"
首先计算:
a + 'a'
由于:
a 是 int
'a' 可以参与整数运算
所以:
5 + 97 = 102
然后:
102 + "itheima"
才发生字符串拼接。
最终得到:
102itheima
而:
"itheima" + a + 'a'
首先执行:
"itheima" + 5
已经变成字符串:
"itheima5"
随后:
"itheima5" + 'a'
继续进行字符串拼接:
itheima5a
因此初学阶段可以用一句话帮助理解:
从左到右,能做数值运算时先做数值运算;一旦进入字符串拼接,后续
+通常继续按照字符串连接处理。
但是更准确的依据仍然是:
当前这一对
+操作数的类型是什么。
2.7 自增与自减运算符
Java 提供:
++
--
用于将变量自身增加或减少 1。
例如:
int count = 10;
count++;
System.out.println(count);
得到:
11
等价思想可以理解为:
count = count + 1;
同理:
count--;
表示:
count = count - 1;
2.8 ++ 写在前面还是后面
可以写:
a++;
也可以写:
++a;
如果单独作为一条语句:
a++;
与:
++a;
最终都会使:
a 增加 1
例如:
int a = 10;
a++;
System.out.println(a);
和:
int a = 10;
++a;
System.out.println(a);
都会输出:
11
真正的区别出现在:
++本身被放进一个更大的表达式中。
2.9 后置自增:先用后加
例如:
int a = 10;
int b = a++;
理解过程:
① 先使用 a 当前的值 10
② 将 10 赋给 b
③ a 再增加 1
最终:
a = 11
b = 10
可以记:
a++ → 先用后加
2.10 前置自增:先加后用
例如:
int a = 10;
int b = ++a;
过程:
① a 先增加 1
② a 变成 11
③ 再把 11 作为表达式结果
④ 赋给 b
最终:
a = 11
b = 11
可以记:
++a → 先加后用
-- 的规则完全对应:
a-- → 先用后减
--a → 先减后用
2.11 工程代码不要滥用复杂自增表达式
虽然 Java 允许:
int result = ++a + b++ - --c;
但是这类代码通常非常难读。
能够写出来:
≠
应该写出来。
工程开发更强调:
正确
+
清晰
+
容易维护
而不是炫技。
因此对于复杂变量变化,宁可拆开:
a++;
b++;
int result = a + b;
也不要故意制造难以理解的表达式。
2.12 基本赋值运算符
Java 最基本的赋值运算符:
=
例如:
int age = 18;
这里并不是数学意义中的:
age 等于 18
而是:
将右侧计算得到的数据保存到左侧变量中。
所以:
age = age + 1;
完全合法。
执行过程应该从右往左理解:
① 读取 age 当前值
② 计算 age + 1
③ 将新结果重新赋值给 age
2.13 = 与 == 不一样
这一点必须彻底区分。
=
是赋值:
int age = 18;
而:
==
是比较是否相等:
boolean result = age == 18;
结果是:
true
所以:
= → 赋值
== → 判断是否相等
2.14 复合赋值运算符
Java 提供:
+=
-=
*=
/=
%=
例如:
int money = 100;
money += 20;
表示:
money 增加 20
对于普通 int 场景,可以粗略理解为:
money = money + 20;
同理:
money -= 10;
money *= 2;
money /= 5;
money %= 3;
分别表示:
减
乘
除
取余
2.15 复合赋值不只是简单文本替换
这一点与上一章类型转换直接相关。
例如:
byte value = 10;
value += 20;
这段代码可以编译。
但是:
byte value = 10;
// value = value + 20;
后者不能直接编译。
为什么?
因为:
byte + int
进行数值提升后:
value + 20
结果是:
int
而:
int → byte
不能直接隐式赋值。
复合赋值:
value += 20;
则包含了向左侧变量类型转换回去的语义。
可以用近似思想理解为:
value = (byte) (value + 20);
所以复合赋值不仅是:
少写几个字符
它还涉及 Java 语言定义的类型转换规则。
这也意味着:
复合赋值同样可能发生数据范围或精度问题。
2.16 关系运算符
关系运算符用于比较数据之间的关系。
常见:
| 运算符 | 含义 |
| ------ | -------- |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| == | 等于 |
| != | 不等于 |
例如:
int score = 80;
System.out.println(score >= 60);
结果:
true
关系表达式最终产生:
boolean
也就是:
true
或者:
false
例如:
int age = 18;
boolean adult = age >= 18;
这里:
age >= 18
就是一个布尔表达式。
2.17 逻辑运算符
一个条件往往还不够。
例如:
手机价格必须大于等于 4000,并且小于等于 6000。
这需要组合两个条件:
price >= 4000
和:
price <= 6000
于是需要逻辑运算符。
常见逻辑运算符:
| 运算符 | 含义 |
| ------ | -------- |
| & | 逻辑与 |
| ` | ` |
| ^ | 逻辑异或 |
| ! | 逻辑非 |
| && | 短路与 |
| ` | |
2.18 逻辑与 &
对于布尔值:
true & true → true
true & false → false
false & true → false
false & false → false
即:
两边都是真,结果才是真。
例如:
boolean result = age >= 18 & age <= 60;
2.19 逻辑或 |
规则:
true | true → true
true | false → true
false | true → true
false | false → false
即:
至少有一边是真,结果就是真。
2.20 逻辑异或 ^
对于布尔值:
true ^ true → false
false ^ false → false
true ^ false → true
false ^ true → true
可以理解为:
两边不同才为 true。
2.21 逻辑非 !
! 用于取反。
例如:
boolean login = true;
System.out.println(!login);
结果:
false
规律:
!true → false
!false → true
2.22 &&:短路与
&& 与 & 在布尔逻辑结果上类似:
两边都为 true,整体才为 true。
但是:
&&
具有短路特性。
例如:
boolean result = false && someExpression;
左边已经是:
false
无论右边是什么:
false && ?
整体都不可能变成 true。
所以:
Java 不再计算右侧表达式。
这就叫:
短路求值(Short-Circuit Evaluation)。
例如:
int number = 0;
boolean result = false && (++number > 0);
System.out.println(number);
右侧:
++number
不会执行。
所以:
number
仍然是:
0
2.23 ||:短路或
|| 同样具有短路特性。
例如:
boolean result = true || someExpression;
左侧已经:
true
那么:
true || ?
无论右边是什么,整体一定都是:
true
因此 Java 不再计算右侧。
2.24 & 与 && 的核心区别
对于布尔表达式:
&
&&
最终逻辑结果通常相同。
但是执行过程不同:
& → 左右两边通常都计算
&& → 左侧 false 时,右侧不再计算
同理:
| → 左右两边通常都计算
|| → 左侧 true 时,右侧不再计算
实际业务条件判断中:
&&
||
使用更加普遍。
不仅能够减少不必要计算,还经常可以避免右侧执行危险操作。
2.25 一个经典短路案例
例如:
int denominator = 0;
boolean valid = denominator != 0
&& 100 / denominator > 2;
先计算:
denominator != 0
结果:
false
因为使用:
&&
右侧:
100 / denominator
就不会执行。
这种写法展示了短路逻辑的重要价值:
后一个条件可以建立在前一个条件已经成立的前提之上。
2.26 三元运算符
Java 提供条件运算符:
? :
基本格式:
条件 ? 条件成立时的结果 : 条件不成立时的结果
例如:
int age = 20;
String result = age >= 18 ? "成年人" : "未成年人";
System.out.println(result);
执行逻辑:
age >= 18 ?
↓
true
↓
"成年人"
如果条件为 false:
选择冒号后面的表达式
2.27 三元运算符适合什么场景
三元运算符适合:
简单的二选一结果。
例如:
int a = 10;
int b = 20;
int max = a > b ? a : b;
或者:
int number = 10;
String type = number % 2 == 0 ? "偶数" : "奇数";
但是如果逻辑非常复杂:
多个条件
多条语句
大量业务操作
多级分支
就不应该为了“代码短”而强行套三元运算。
后面学习 if 后,应根据场景选择更加清晰的方案。
三、使用方法
3.1 算术运算完整示例
public class ArithmeticDemo {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b);
System.out.println((double) a / b);
System.out.println(a % b);
}
}
重点观察:
a / b
与:
(double) a / b
之间的区别。
3.2 点赞数量变化
public class LikeDemo {
public static void main(String[] args) {
int count = 0;
count++;
count++;
count++;
System.out.println("点赞数:" + count);
count--;
System.out.println("取消点赞后:" + count);
}
}
3.3 手机价格范围判断
public class PriceDemo {
public static void main(String[] args) {
double price = 5000;
boolean suitable =
price >= 4000 && price <= 6000;
System.out.println(suitable);
}
}
逻辑模型:
价格 >= 4000
&&
价格 <= 6000
3.4 判断奇偶
public class EvenDemo {
public static void main(String[] args) {
int number = 25;
String result =
number % 2 == 0 ? "偶数" : "奇数";
System.out.println(result);
}
}
这里综合使用了:
%
==
? :
3.5 两个数取最大值
public class MaxDemo {
public static void main(String[] args) {
int a = 20;
int b = 30;
int max = a > b ? a : b;
System.out.println(max);
}
}
四、原理与进阶
4.1 表达式计算必须同时关注值和类型
学习运算符时最容易出现一个错误:
只算数值,不判断类型。
例如:
byte a = 10;
byte b = 20;
// byte result = a + b;
数学上:
10 + 20 = 30
但 Java 还需要考虑:
a + b 的表达式类型是什么?
根据数值提升规则:
byte + byte
会按照:
int + int
计算。
因此表达式类型是:
int
所以分析 Java 表达式应该建立完整思维:
操作数
↓
操作数类型
↓
是否发生类型提升
↓
执行什么运算
↓
得到什么值
↓
结果是什么类型
4.2 + 的真正判断标准是类型
有些入门教程会说:
能算则算,不能算就连接。
这个说法适合快速入门,但不够严谨。
更准确的规则是:
如果二元 + 的某个操作数是 String:
字符串拼接
否则操作数必须能够参与数值运算:
数值加法
例如:
1 + 2 + "3"
按照从左到右:
1 + 2
↓
3
然后:
3 + "3"
↓
"33"
而:
"1" + 2 + 3
首先:
"1" + 2
↓
"12"
然后:
"12" + 3
↓
"123"
4.3 复合赋值只计算左侧一次
对于:
E1 op= E2
Java 的语义不仅包含类型转换,而且左侧表达式只会被计算一次。
对于初学阶段的普通变量:
a += b;
不容易看出差异。
但随着以后学习:
数组
对象
方法调用
这条规则会变得更加重要。
目前需要掌握的核心是:
+=
不能机械地认为只是把:
a = a +
缩写了一下。
4.4 ++ 和 -- 会写回原变量
例如:
int a = 10;
int b = a++;
这里实际上存在两个结果:
表达式 a++ 的结果 → 10
变量 a 更新后的结果 → 11
因此:
表达式的值
和:
变量最终保存的值
必须区分。
这是理解前置和后置自增最关键的一点。
五、实践应用
真实业务中的大量条件,本质上都是运算符组合。
例如登录条件:
boolean allowLogin =
accountExists
&& passwordCorrect
&& !accountLocked;
商品筛选:
boolean match =
price >= minPrice
&& price <= maxPrice;
权限判断:
boolean allow =
isAdmin || isOwner;
数据校验:
boolean legal =
age >= 0 && age <= 150;
因此:
运算符是后续
if、switch、循环、算法和业务逻辑的基础语言。
如果连表达式都分析不清楚,后面流程控制就很容易出现“代码能看懂,但自己写条件总出错”的情况。
六、常见问题
6.1 为什么 5 / 2 不是 2.5?
因为:
int / int
执行整数运算。
应该让至少一侧进入浮点类型:
5.0 / 2
或者:
(double) 5 / 2
6.2 % 只能用于判断奇偶吗?
不是。
奇偶判断只是最常见的应用之一。
% 还可以用于:
周期
轮转
数字拆分
倍数判断
时间换算
6.3 a++ 和 ++a 哪个更快?
不应该以这种方式选择。
现代 Java 编译与运行环境下,真正应该考虑的是:
你需要“先使用旧值”还是“先得到新值”。
如果只是独立执行:
a++;
或:
++a;
重点是代码语义,而不是幻想中的性能差距。
6.4 a += 1 和 a = a + 1 完全一样吗?
对于普通 int 场景结果经常相同,但语言语义不完全相同。
尤其对于:
byte
short
char
复合赋值包含向左侧变量类型转换回去的规则。
6.5 & 和 && 应该用哪个?
普通业务布尔条件通常优先:
&&
因为它具有短路能力。
但两者并不是同一个运算符。
另外,&、|、^ 还可以用于整数的按位运算,这部分在真正遇到位运算场景时再深入学习。
6.6 == 能不能比较字符串内容?
不要把:
==
简单理解为所有对象的“内容相等”。
对于基本数据类型,本章可以用它比较数值或布尔值。
对于 String 等引用类型:
==
涉及引用比较。
字符串内容比较将在 String 章节系统学习。
6.7 三元运算符一定比 if 好吗?
不是。
三元运算符适合:
条件 ? 值1 : 值2
这种简单二选一表达式。
复杂业务逻辑更应该关注:
清晰
可读
容易维护
而不是单纯追求代码短。
6.8 运算符优先级需要全部背下来吗?
没有必要机械背完整优先级表。
常用规则应该逐渐熟悉,例如:
算术
比较
逻辑
赋值
但只要表达式已经复杂到让人犹豫:
主动加括号。
例如:
boolean result =
(score >= 60)
&& (attendance >= 80);
比依靠读者背优先级更加可靠。
七、练习与验收
7.1 知识问答
- Java 的算术运算符有哪些?
- 为什么
5 / 2的结果是2? - 如何让
5 / 2得到2.5?至少写出两种方式。 %运算符有哪些典型用途?+在什么情况下表示字符串拼接?- 为什么
"abc" + 1 + 2与1 + 2 + "abc"的结果不同? ++a与a++单独成句时有什么共同点?++a与a++放入表达式时有什么区别?=与==分别表示什么?+=、-=、*=、/=、%=分别表示什么?- 为什么
byte b = 10; b += 20;可以编译? - 关系运算符最终产生什么类型的数据?
&和&&有什么区别?|和||有什么区别?^对布尔值有什么规则?- 什么叫短路求值?
- 三元运算符的基本语法是什么?
- 为什么复杂表达式通常建议主动添加括号?
7.2 代码阅读
禁止运行,预测结果:
public class OperatorRead01 {
public static void main(String[] args) {
int a = 5;
System.out.println("abc" + a);
System.out.println(a + 5);
System.out.println("itheima" + a + 'a');
System.out.println(a + 'a' + "itheima");
}
}
要求:
- 逐行预测结果。
- 写出每一个
+执行时左右操作数的类型。 - 解释最后一行为什么首先发生数值运算。
继续分析:
public class OperatorRead02 {
public static void main(String[] args) {
int a = 10;
int x = ++a;
int b = 10;
int y = b++;
System.out.println(a + "," + x);
System.out.println(b + "," + y);
}
}
要求:
- 不运行代码预测结果。
- 用“先加后用”和“先用后加”解释整个过程。
继续分析:
public class OperatorRead03 {
public static void main(String[] args) {
int number = 0;
boolean a = false && (++number > 0);
boolean b = true || (++number > 0);
System.out.println(a);
System.out.println(b);
System.out.println(number);
}
}
要求解释:
- 哪些右侧表达式没有执行?
- 为什么?
number最终是多少?
7.3 手写代码
- 分别使用
+ - * / %对两个整数完成运算。 - 分别使用两种方式让
5 / 2得到2.5。 - 模拟点赞数量连续增加三次,再取消一次点赞。
- 使用
%判断一个整数是奇数还是偶数。 - 使用三元运算符找出两个整数的最大值。
- 判断某手机价格是否处于 4000~6000 元之间。
- 使用逻辑运算符实现“年龄处于 18~60 岁之间”的判断。
- 自己设计代码证明
&与&&在执行右侧表达式方面存在区别。
7.4 Debug
下面代码存在问题:
public class OperatorDebug01 {
public static void main(String[] args) {
int a = 5;
double result = a / 2;
System.out.println(result);
}
}
需求:
- 判断为什么结果没有得到预期的
2.5。 - 问题发生在赋值阶段还是除法阶段?
- 给出至少两种合理修复方式。
继续分析:
public class OperatorDebug02 {
public static void main(String[] args) {
byte value = 10;
value = value + 20;
System.out.println(value);
}
}
要求:
- 判断为什么不能直接编译。
- 结合上一章类型提升解释原因。
- 分别使用合理的普通赋值和复合赋值完成修复。
- 比较两种方案的类型转换含义。
7.5 综合训练
设计一个简单的“商品筛选判断器”。
固定以下数据:
商品价格:5299
用户最低预算:4000
用户最高预算:6000
库存:10
会员状态:true
程序至少需要判断:
价格是否符合预算
商品是否有库存
用户是否为会员
是否同时满足购买条件
要求:
- 至少使用关系运算符。
- 至少使用
&&或||。 - 至少使用一次
!或三元运算符。 - 每一个复杂条件都使用有语义的
boolean变量保存。 - 不允许把所有逻辑强行塞进一条超长表达式。
7.6 本章验收
关闭资料后确认:
- [ ] 能解释
5 / 2与5.0 / 2的区别。 - [ ] 能熟练使用
%。 - [ ] 能独立分析连续字符串
+的执行结果。 - [ ] 能解释
a++和++a的区别。 - [ ] 能区分
=与==。 - [ ] 能解释复合赋值中的隐式类型转换。
- [ ] 能熟练使用六种关系运算符。
- [ ] 能写出
& | ^ ! && ||的布尔规则。 - [ ] 能解释
&&和||的短路过程。 - [ ] 能正确使用三元运算符。
- [ ] 能主动使用括号提高复杂表达式的可读性。
如果你仍然主要依赖“看到符号猜意思”,而不能根据操作数类型、运算顺序和表达式类型分析结果,则本章还没有真正掌握。