钩子:i = i++ 之后,输出还是 10
接着看今天的代码,别运行,先猜输出:
public class Demo {
public static void main(String[] args) {
int i = 10;
i = i++;
System.out.println(i);
}
}
给 i 赋值它自增之后的结果,输出 11?
错。输出是 10。
这道题在面试里出现过无数次,答对的人不到一半。今天这篇讲清楚它,顺便把运算符里另外三个新手必踩的坑一起排掉。
01 算术运算符速查表(建议收藏)
| 运算符 | 作用 | 示例 | 结果 |
|---|---|---|---|
| + - * / | 加减乘除 | 10 / 3 | 3(不是 3.33!) |
| % | 取余(取模) | 10 % 3 | 1 |
| ++ | 自增 1 | i++ 或 ++i | 见下文 |
| -- | 自减 1 | i-- 或 --i | 同 ++ 的逻辑 |
先记住一条:两个整数相除,结果还是整数,小数部分直接砍掉,不四舍五入。
02 i = i++ 输出 10:一条执行过程讲清楚
i++ 是"后置自增",执行分三步:
第 1 步:把 i 当前的值(10)暂存起来
第 2 步:i 自己加 1,此时 i = 11
第 3 步:把暂存的旧值(10)赋回给 i,i 又变回 10
一句话:先取旧值干别的,最后才自增——但赋值用的正是那个旧值。

++i(前置自增)反过来:先加 1,再用新值。所以 i = ++i 才会输出 11。
单独写一行 i++; 时两者没区别,区别只在和赋值、比较、传参混在一起时才出现。
03 整数除法的坑:10 / 3 = 3
int a = 10 / 3; // 3,小数直接砍掉
double b = 10 / 3; // 3.0 —— 注意!不是 3.33
double c = 10 / 3.0; // 3.3333...
最坑的是第二行:你把结果赋给了 double,以为有精度——没用,除法发生在赋值之前,10 / 3 早就变成 3 了。
想拿到小数结果,必须让任意一个操作数是浮点数(写成 10.0 / 3 或 10 / 3.0)。
04 b = b + 1 报错,b += 1 却通过?
接着上一篇的类型转换,看这个:
byte b = 10;
b = b + 1; // 编译报错:不兼容的类型
b += 1; // 正常通过,b = 11
为什么?b + 1 中,byte 会先自动提升成 int(上一篇讲的自动类型转换),int 再赋回给 byte 就是大转小,必须强转,所以报错。
而 +=、-=、*= 这类复合赋值运算符自带强制转换,相当于 b = (byte)(b + 1),编译器替你转了。
同理,short 和 char 也有这个问题:
short s = 1;
s = s + 1; // 报错
s += 1; // 通过
本文示例代码均已本地实测通过,可直接运行。
橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。