Java中i++和++i在字节码层面有什么区别

前情提要

在这里插入图片描述

前置知识

  • Java运行时数据区中的虚拟机栈(Java Virtual Machine Stacks)
    • 栈帧(Frame)
      • Local Variables(局部变量表)
      • Operand Stack(操作数栈)

先看一道题

    public static void main(String[] args) {
        int i = 8;
        i = i++;	// 输出8
        //i = ++i;	// 输出9
        System.out.println(i);
    }

我们都知道 i++ 是先赋值在运算 所以输出8。++i 先运算在赋值 所以输出9。
但是你知道在字节码层面是如何实现的么?
使用 idea 插件 jclasslib 查看字节码文件

 0 bipush 8 
 2 istore_1
 3 iload_1
 4 iinc 1 by 1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return

看不懂没事,我们先来看看上面几个指令是什么意思

指令

  • bipush
    > The immediate byte is sign-extended to an int value. That value is pushed onto the operand stack.
    将一个byte带符号扩展为int,然后压入操作数栈。简称压栈。
  • istore
    在这里插入图片描述
    弹出操作数栈栈顶的数字,放到局部变量表下标为n的位置
  • iload_< n >
    在这里插入图片描述

分析i++字节码文件

局部变量表
在这里插入图片描述

 0 bipush 8 // 把 8 压栈
 2 istore_1 // 把 8 弹出,放入局部变量表中下标为 1 的位置
 3 iload_1 // 把局部变量表中下标为 1 的数压栈,即把 8 压栈
 4 iinc 1 by 1 // 把局部变量表下标为 1 的数加 1。注意,此时局部变量表中 i 的值等于 9 了。栈中的 i 还是 8
 7 istore_1 //把 8 弹出,放入局部变量表中下标为 1 的位置。注意,此时局部变量表中i的值又从 9 变回 8 了。
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return

int i = 8 相当于以下两条指令:

 0 bipush 8 
 2 istore_1

i = i++ 相当于以下三条指令:

iload_1
iinc 1 by 1
istore_1

所以 i++ 不管多少次,最后输出的都是 8

public class TestIPulsPlus {
    public static void main(String[] args) {
        int i = 8;
        for (int j = 0; j < 10; j++) {
            i = i++;
        }
//        i = ++i;
        System.out.println(i);
    }
}

分析++i字节码文件

java代码:

public class TestIPulsPlus {
    public static void main(String[] args) {
        int i = 8;
        i = ++i;
        System.out.println(i);
    }
}

使用 idea 插件 jclasslib 查看字节码文件

 0 bipush 8
 2 istore_1
 3 iinc 1 by 1
 6 iload_1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return

把8压栈,弹出,放到局部变量表,8加1变成9,把9压栈,把9弹出放到局部变量表。

总结

自增操作是在局部变量表中进行的。

参考资料

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.bipush

思考题

下面我们再做一道题来巩固一下

    public static void main(String[] args) {
        int i = 1;
        for (int j = 0; j < 10; j++) {
            i = i++;
        }
        int k = i++;
        int m = i + ++i * i++;
        System.out.println("i = " + i);
        System.out.println("k = " + k);
        System.out.println("m = " + m);
    }

请问 i、k、m 依次输出多少?

i = 4
k = 1
m = 11

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值