Welcome everyone

从字节码角度理解 i++ 和 ++i

java 汪明鑫 74浏览 0评论

先看一段代码

public class NumIncreTest {
    public static void main(String[] args) {

        int num = 0;
        for (int i = 0; i < 50; i++) {
            num = num++;
        }

        System.out.println(num);  
    }

}

输出是0

为啥是0,不是50呢?

早期我们大多是这样理解的, ++操作是滞后于赋值操作的

num = num;

num ++;

那为啥是这样的呢?

我们从字节码角度来看下

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: iconst_0
         1: istore_1
         2: iconst_0
         3: istore_2
         4: iload_2
         5: bipush        50
         7: if_icmpge     21

        10: iload_1
        11: iinc          1, 1
        14: istore_1

        15: iinc          2, 1
        18: goto          4
        21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: iload_1
        25: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        28: return

关键看字节码 10~14行

10: iload_1

11: iinc 1, 1

14: istore_1

先把局部变量表的slot1 的变量num 加载出来,值为0,栈中的数是0

再对局部变量表的slot1 + 1,得1

再把栈中的0 store 到局部变量表的slot1 ,把1覆盖了,又成0

循环50次,还是0。。。

再来一个++i的例子

public class NumIncreTest1 {
    public static void main(String[] args) {
        int num = 0;
        for (int i = 0; i < 50; i++) {
            num = ++num;
        }

        System.out.println(num);  // 50
    }
}
这个输出是50
同样看下字节码
public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: iconst_0
         1: istore_1
         2: iconst_0
         3: istore_2
         4: iload_2
         5: bipush        50
         7: if_icmpge     21
        10: iinc          1, 1
        13: iload_1
        14: istore_1
        15: iinc          2, 1
        18: goto          4
        21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: iload_1
        25: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        28: return


可以看下区别哈~

10: iinc 1, 1

13: iload_1

14: istore_1

++i 是先在局部变量表做++操作,再load

因此++的值可以读到,生效

i++++i
10: iload_1
11: iinc 1, 1
14: istore_1
10: iinc 1, 1
13: iload_1
14: istore_1

有了前面的铺垫,我们再来看一个稍难点的

public class NumIncreTest2 {
    public static void main(String[] args) {
        int num = 0;

        num = num++ + ++num;
        System.out.println(num);
    }
}

先揭晓答案 2

看下字节码

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: iinc          1, 1
         6: iinc          1, 1
         9: iload_1
        10: iadd
        11: istore_1
        12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        15: iload_1
        16: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        19: return

把字节码翻译成图就是上面这个吊样子啦

如果用伪代码来理解就是

num = 0;

tmp1 = num;
num = num + 1;

num = num + 1;
tmp2 = num;

tmpSum = tmp1 + tmp2;

num = tmpSum;

转载请注明:汪明鑫的个人博客 » 从字节码角度理解 i++ 和 ++i

喜欢 (2)

说点什么

您将是第一位评论人!

提醒
avatar
wpDiscuz