第4章 运算符与表达式
第4章 运算符与表达式
数据定义好之后,就要对数据进行运算。本节系统学习 Java 的各类运算符:算术、赋值、比较、逻辑、三元等。
一、算术运算符
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
+ | 加 | 7 + 3 | 10 |
- | 减 | 7 - 3 | 4 |
* | 乘 | 7 * 3 | 21 |
/ | 除 | 7 / 3 | 2(整数相除取整) |
% | 取余 | 7 % 3 | 1 |
System.out.println(7/3);// 2:整数除法直接丢弃小数System.out.println(7.0/3);// 2.3333333333333335:有小数参与就是浮点除法System.out.println(7%3);// 1:7 = 3*2 + 1为什么
7 / 3是 2?因为 int 类型装不下小数,Java 规定"整数 ÷ 整数"结果仍是整数,小数部分直接丢弃(不是四舍五入,3.99 也会变成 3)。要保留小数,至少让一边变成浮点数。另外:整数除以 0 会抛ArithmeticException,浮点除以 0 得Infinity,注意分母别为 0。
// 取余 % 的经典应用:判断奇偶、拆数字System.out.println(123%2);// 1:奇数System.out.println(123%10);// 3:个位数字System.out.println(123/10%10);// 2:十位数字自增自减运算符
inta=10;a++;// a = 11,自增a--;// a = 10,自减intb=10;intc=b++;// c = 10:先取值再自增(后缀),b 变成 11intd=++b;// d = 12:先自增再取值(前缀),b 变成 12口诀:前缀 ++ 先用后加,后缀 ++ 先加后用(站在使用者的角度看)。
为什么要有++?因为i = i + 1在循环里写得太啰嗦,i++一行搞定。单独成行时,前缀和后缀结果完全一样,只有混进表达式里才有区别(见扩展知识与易错点)。
二、赋值运算符
=是赋值,不是数学中的等号:
intx=5;x+=3;// x = x + 3 = 8x-=2;// x = 8 - 2 = 6x*=4;// x = 24x/=6;// x = 4x%=3;// x = 1复合赋值运算符+=、-=、*=、/=、%=能让代码更简洁,且自带隐式强转:
// 复合赋值自带隐式强转,byte 也能直接做运算byteb=10;b+=5;// 编译通过:等价于 b = (byte)(b + 5)// b = b + 5; // 编译报错:b + 5 是 int,不能直接赋给 byte三、比较运算符
结果永远是布尔值true/false:
| 运算符 | 说明 | 示例 | 结果 |
|---|---|---|---|
== | 相等 | 5 == 5 | true |
!= | 不等 | 5 != 5 | false |
> | 大于 | 5 > 3 | true |
< | 小于 | 5 < 3 | false |
>= | 大于等于 | 5 >= 5 | true |
<= | 小于等于 | 3 <= 5 | true |
// 比较结果可以直接存进 boolean,后面给 if 用booleanflag=5>3;// trueSystem.out.println(flag);System.out.println('A'==65);// true:'A' 的 Unicode 编号就是 65注意:基本类型用
==比较值;String 等引用类型用==比较的是地址,比较内容要用equals()方法,后面字符串章节会重点讲。
四、逻辑运算符
用于连接多个布尔表达式:
| 运算符 | 说明 | 示例 |
|---|---|---|
&& | 短路与:两边都为 true 才为 true | a > 0 && b > 0 |
|| | 短路或:一边为 true 即为 true | a > 0 || b > 0 |
! | 非:取反 | !true→ false |
intage=20;booleanisAdult=age>=18;// truebooleancanDrive=isAdult&&age<70;// true:满足两个条件booleanisKid=!isAdult;// false短路特性(重要)
&&左边为 false 时,右边不再执行;||左边为 true 时,右边不再执行:
intx=10;booleanr=(x>100)&&(x++>0);// 右边不执行,x 仍是 10这个特性常用于避免空指针,name != null && name.length() > 0就是最经典的写法,具体实战放到"扩展知识"里演示。
五、三元运算符
格式:条件 ? 值1 : 值2
intscore=85;Stringresult=score>=60?"及格":"不及格";System.out.println(result);// 及格它是 if-else 的简写,但表达式必须有返回值。可以嵌套,但超过两层可读性很差,不建议。求最大值这类"二选一取值"用三元最顺手:int max = a > b ? a : b;
六、运算符优先级
从高到低常用顺序:
- 括号
() - 自增自减
++ -- - 乘除余
* / % - 加减
+ - - 比较
> < >= <= - 相等
== != - 逻辑与
&& - 逻辑或
|| - 赋值
= += -= ...
建议:不确定优先级时就用括号,代码可读性比省几个括号重要得多。
intresult=(1+2)*(3+4)-5/2;// = 3 * 7 - 2 = 19七、字符串拼接
+遇到字符串时是拼接操作:
Stringname="张三";intage=25;System.out.println("姓名:"+name+",年龄:"+age);// 姓名:张三,年龄:25任何类型与字符串相加都会先转成字符串再拼接。后面字符串章节会讲为什么循环中拼接字符串性能差(StringBuilder 的由来)。
// 任何类型遇到 "+ 字符串" 都先转成字符串;拼接方向从左往右System.out.println("结果是:"+(1+2));// 结果是:3:括号里先算加法System.out.println("结果是:"+1+2);// 结果是:12:直接拼接八、扩展知识
1. 位运算入门(& | ^ << >>)
面试常考、底层代码常用。注意区分:&&、||是逻辑运算,结果只有 true/false;&、|是位运算,直接操作二进制位。
| 运算符 | 名称 | 规则 | 示例 |
|---|---|---|---|
& | 按位与 | 两位都是 1 结果才是 1 | 6 & 3= 2 |
| | 按位或 | 有一位是 1 结果就是 1 | 6 | 3= 7 |
^ | 按位异或 | 两位不同为 1,相同为 0 | 6 ^ 3= 5 |
<< | 左移 | 整体左移,低位补 0 | 6 << 1= 12 |
>> | 右移 | 整体右移,高位补符号位 | 6 >> 1= 3 |
// 移位:左移一位 = 乘 2,右移一位 = 整除 2System.out.println(6<<1);// 12System.out.println(6>>1);// 3// 应用:& 1 判断奇偶;n & (n-1) == 0 判断 2 的幂System.out.println((7&1)==0?"偶数":"奇数");// 奇数System.out.println(16>0&&(16&15)==0);// true:16 = 2^42. 短路求值的判空应用
&&短路特性在"判空 + 用值"组合里几乎是标配写法:
// 配合三元做"兜底显示",配置或输入可能是 nullStrings=getInput();// 假设这个方法可能返回 nullStringshow=(s!=null&&!s.isEmpty())?s:"(空)";System.out.println(show);// (空):null 被安全兜底3. 自增自减的底层原理
一句话概括:i++是"先把 i 的当前值作为表达式结果,再自增";++i是"先自增,再把新值作为表达式结果"。
// 后缀:拿到的是自增前的值;前缀:拿到的是自增后的新值inta=5;intb=a+++a++;// 第一次取 5,a 变 6;第二次取 6,a 变 7 → 5 + 6 = 11intx=5;inty=++x+++x;// 先变 6,再变 7 → 6 + 7 = 13System.out.println(b+" "+y);// 11 13这种先后顺序在 JVM 底层对应专门的字节码指令。记住结论即可:别把自增写进复杂表达式,单独一行用,谁都看得懂。
九、易错点
1. 整数除法直接取整
// ❌ 想要 2.5,却得到 2.0(5/2 先按 int 算出 2)doubled1=5/2;System.out.println(d1);// 2.0// ✅ 至少一边是浮点数,或显式强转doubled2=5/2.0;// 2.5doubled3=(double)5/2;// 2.52. % 取余对负数的符号
// ❌ 以为 -5 % 2 是 1,实际是 -1(符号跟随被除数)System.out.println(-5%2);// -1System.out.println(5%-2);// 1// ✅ 需要"非负余数"时,先对绝对值取余intr=Math.abs(-5)%2;// 13. 用 == 比较浮点数
// ❌ 0.1 + 0.2 实际是 0.30000000000000004,和 0.3 永不相等doublea=0.1+0.2;if(a==0.3){// false!里面永远不会执行System.out.println("相等");}// ✅ 用"差值的绝对值小于一个极小值"判断近似相等if(Math.abs(a-0.3)<0.000001){System.out.println("近似相等");// 走这里}4. 记不住优先级却不用括号
// ❌ 依赖记忆硬写,隔几天自己都看不懂intr=1+2*3>>1;// (1 + 6) >> 1 = 3// ✅ 用括号把意图写清楚,可读性优先intr2=(1+2*3)>>1;// 3,一眼看懂5. a++ 与 ++a 混用
// ❌ 前缀后缀混进一个表达式,结果全靠猜inti=1;intj=i+++++i;// 1 + 3 = 4,i 变成 3// ✅ 自增自减单独成行,前缀后缀完全等价,行为清晰i=1;i++;++i;System.out.println(i);// 3十、小结
本系列统一按 JDK 8、JDK 11、JDK 17 三个 LTS 版本讲解。运算符这部分三个版本写法完全一致,你用哪个版本练习都一样,不用担心差异。
- 整数除法取整、取余
%用途广泛(判断奇偶、取某位数字) ==比较基本类型的值,引用类型比较内容用equals&&、||有短路特性,判空场景很好用- 三元是简单分支的语法糖,嵌套别超过两层;优先级记不住就用括号
- 位运算是加分项,业务代码别滥用;自增自减单独成行使用
下一节学习条件控制语句 if / switch。
下一篇:第5章 条件控制:if / switch
