zoukankan      html  css  js  c++  java
  • 为什么i=i++后,i的值不变(深入解析)

    在Java中,运行以下代码:

    1         int i=10;
    2         i=i++;
    3         System.out.println(i);

    得到的结果仍然为10,为什么呢?理论上,运算的过程不应该是i首先把10取出来,赋值给i,然后i再自增1,结果不该是11吗?

    原因还是要从反编译得到的汇编源码看起。在cmd窗口,输入命令javap -c Demo(Demo是class的文件名),可以得到反编译的汇编源码,

    下面我们一步步来,先将两行简单的代码反编译一下。

    1         int i=10;
    2         int j=9;

    上述两行代码的反编译结果是

    1        0: bipush        10      //将常量10压入操作数栈 
    2        2: istore_1                  //将操作数栈顶元素(10)弹出,存入局部变量位置1处
    3        3: bipush        9           //将常量9压入操作数栈
    4        5: istore_2                  //将操作数栈顶元素(9)弹出,存入局部变量位置2处
    5        6: return

    上下代码可以很简单的对应起来,可以初步看出,赋值语句在汇编其实是有两步,第一步压栈(操作数栈),第二部(出栈并存储至局部变量处)。

    为了进行验证,再多加一行代码,如下

    1         int i=10;
    2         int j=9;
    3         j=i;

    同样,反编译看汇编如下:

    1        0: bipush        10
    2        2: istore_1
    3        3: bipush        9
    4        5: istore_2
    5        6: iload_1
    6        7: istore_2
    7        8: return

    很明显的可以看到,j=i这一句,并不是直接把局部变量位置1的值赋值给局部变量2,而是先压入操作数栈,再弹出存储在局部变量位置2处!

    下面我们把最开头的i=i++进行一下反编译,得到的结果如下。

     1 public class Demo {
     2   public Demo();
     3     Code:
     4        0: aload_0
     5        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
     6        4: return
     7 
     8   public static void main(java.lang.String[]);
     9     Code:
    10        0: bipush        10           //将常量10压入操作数栈
    11        2: istore_1                   //将操作数的栈顶元素(10)出栈,存入局部变量表1的位置处(这两句话完成了i=10的赋值操作)
    12        3: iload_1                    //将局部变量表1位置的值压入操作数栈
    13        4: iinc          1, 1         //局部变量表1位置的值自增1
    14        7: istore_1            //重新将操作数栈顶的值(10)出栈存入局部变量表1的位置处
    15        8: return
    16 }

    只需要从第10行看起就可以了。

    可以很明显的看到,自增过程是发生在压栈和出栈中间,所以最后出栈的值会把自增的结果覆盖,导致自增其实是没有作用的。

    其实还可以得出一个结论,就是自增和普通的运算的步骤是不同的。自增是直接在局部变量区加1,而运算要进行压栈和出栈操作。

    为了验证这句最关键的话,我们把下面代码进行一次反编译。

    1         int i=10;
    2         i++;
    3         i=i+1;

    得到的反编译结果如下:

    1        0: bipush        10
    2        2: istore_1
    3        3: iinc          1, 1
    4        6: iload_1
    5        7: iconst_1
    6        8: iadd
    7        9: istore_1
    8       10: return

    这下很明显了,i++就只有一句话,iinc    1,1,代表在局部变量位置1处的值自增1,而i=i+1则是先把局部变量1位置处的值压栈,再把常量1压栈,再相加出栈,一共四句话!

    因此,从内存的角度来看,i=i+1和i++是不同的,也就是说:

    i=i++这句话与i=i=i++是不等价的!!!

    明白了这个道理,我想再看这个题应该就没有那么恶心了!

  • 相关阅读:
    整合了一个命令行程序的框架
    CentOS下mysql数据库data目录迁移和配置优化
    关于华硕主板的图像输出设置
    在jetson tx1下编译安装opencv3.2的一点小总结
    安装pydev 但是没有pydev工程选项
    关于PID控制的认识
    notebook( office + matlab)
    vmware 后台运行不能恢复
    将必应设置成chrome的默认搜索引擎
    centOS 7 apache 不能访问
  • 原文地址:https://www.cnblogs.com/haojiejiejie/p/8685986.html
Copyright © 2011-2022 走看看