社交媒体

运算符与 i++ 的坑

运算符与 i++ 的坑

钩子: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

一句话:先取旧值干别的,最后才自增——但赋值用的正是那个旧值。

08-i=i++三步执行图.png

++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;      // 通过

本文示例代码均已本地实测通过,可直接运行。


橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。