通过画图的方式理解java中自增操作为什么是0

结论

先上代码和结论:

public static void main(String[] args) {
        int i = 0;
        int x = 0;
        while (i < 10){
            x = x++;
            i++;
        }
        System.out.println(i);  // 10
        System.out.println(x);  // 0
    }
}

在这里插入图片描述

结论:

x++是先返回值再进行计算,由于语句还没结束,当前返回值是0,然后将0返回赋值给x,最后x==0;

分析

我们这里根据字节码操作指令进行分析,如下是反编译后的文件
在这里插入图片描述
这里0-3行是给变量i和x赋值0的操作
第四行iload_1的操作是将栈帧中局部变量表中第一个槽位中的值压入操作数栈中;

虚拟机栈:
Java 虚拟机栈:Java Virtual Machine Stacks,每个线程运行时所需要的内存

  • 每个方法被执行时,都会在虚拟机栈中创建一个栈帧 stack frame(一个方法一个栈帧

  • Java 虚拟机规范允许 Java 栈的大小是动态的或者是固定不变的

  • 虚拟机栈是每个线程私有的,每个线程只能有一个活动栈帧,对应方法调用到执行完成的整个过程

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存,每个栈帧中存储着:

  • 局部变量表:存储方法里的 Java 基本数据类型以及对象的引用

  • 动态链接:也叫指向运行时常量池的方法引用

  • 方法返回地址:方法正常退出或者异常退出的定义

  • 操作数栈或表达式栈和其他一些附加信息

这里我们画图理解一下
在这里插入图片描述

  1. 字节码文件中第四行的操作如上所示,iload_1就是将一号槽位的值压入栈中
  2. 第五行 bipush jvm讲一个整形常量压入栈中,也就是判断条件中的i<10中的10压入操作数栈中
  3. 第七行中if_icmpge的作用是判断 i < 10 中如果 i > 10 ,则跳转到第21行

21 - 32 行输出i和x的值
System.out.println(i); // 10
System.out.println(x); // 0

  1. 第十行将局部变量表中槽位2的值压入栈中,也就是x = 0;
  2. 十一行iinc的作用是自增,后面的 2 1 是指将2号槽位的值自增1
  3. 十四行则是将栈顶层的元素弹出,返回给操作数栈中的2号元素
  4. 十八行goto的作用是跳转 , 4 是跳转到第四行

为什么 x 自增后需要弹出栈而 i 自增后不需要弹出栈?

因为java源代码中 x = x++;i++;x是自增后又做了一遍赋值操作,所以需要将栈中的值弹出返回给局部变量表中对应槽位进行赋值。!!!但是x = x++;运算结果为0的根本原因也是出自于此,在第一次循环时,x 为 0,x ++是先赋值后运算,先将 0 压入栈中,然后 i ++ 进行自增操作 ,局部变量表中的值自增为1 ,最后由于 x = x++;又做了一遍将x的值赋值给x的操作,也就是将操作数栈中的x值弹出赋值给局部变量表中,此时操作数栈中x值为0,赋值给局部变量表中,x从原先自增的1 又变成了 0 ,循环十次之后,输出结果还是0;

通过画图理解一下:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值