i++和++i的区别

直接上两个网上很经典的demo

例子1

        int i = 1;
        int j = i++;

        System.out.println(i);
        System.out.println(j);

答案:输出2和1

直接反编译class文件,得到前两行的java指令,分析如下


j=i++.gif

可以看出来,i++分为两iload和iinc,所以j=i++会先将i压入操作数栈,再对变量i自加,所以下一步操作从操作数栈取到的i是自加之前的。

例子2

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

答案:输出1
再次观察java指令


i=i++.gif

所以i变量并不是没有自加,而是变量自加后又被操作数栈中的原始i赋值了,所以i看起来没变化

例子3

接下来看看++i是什么样子

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

输出2
再次观察java指令


i=++i.gif

可以看到,i=++i相当于iinc和iload,所以操作数栈中存储的是自增之后的i,这样下次操作用的就是自增之后的i。

于是乎,我得到了大学老师告知的结论:

i++,i在语句结束后自增,当前语句使用的是原始i
++i,先对i进行自增,当前语句使用的是自增之后的i

上面的结论得到了System.out.println(i++)和System.out.printlin(++i)的证实
但是却不严谨,如下面的例子

例子4

        int i = 1;
        int[] arr = new int[10];

        arr[i++] = 10 - i;
        System.out.println(arr[1]);

输出8
按照之前的理解, arr[i++] = 10 - i; 中的i应该是1,所以答案是arr[1]=10-1=9啊,截取该行代码的java指令如下

      11: aload_2 #加载arr数组到操作数栈
      12: iload_1 #加载i到操作数栈 (arr[i++] = arr[1])
      13: iinc          1, 1  #i变量自增(i=2)
      16: bipush        10 #加载10到操作数栈
      18: iload_1 #加载i到操作数栈 (2)
      19: isub  #执行减法 10-2=10-2=8
      20: iastore #arr[i]=8

可以看到, 当编译器遇到i++后,确实是先iload然后iinc,但是后面又遇到了10-i,这时再次从变量栈加载i(2)到操作数栈,所以10-i = 2;

所以结论再精确点,应为

当语句中只有一个i:
i++,i在语句结束后自增,当前语句使用的是原始i
++i,先对i进行自增,当前语句使用的是自增之后的i
当语句中有多个i:
i++,该表达式之前的i为原始i,该表达式为原始i,该表达式之后i为自增后的i
++i, 该表达式之前的i为原始i,该表达式为自增后的i,该表达式之后的i为自增后的i

验证下:

        int i = 1;
        int[] arr = new int[]{2, 4, 6, 8, 10};
        int[] arr1 = new int[5];

        arr1[i] = arr[i++] - i; //arr1[1]=arr[1]-2

输出 [0,2,0,0,0]

        int i = 1;
        int[] arr = new int[]{2, 4, 6, 8, 10};
        int[] arr1 = new int[5];

        arr1[i] = arr[++i] - i;// arr1[1]=arr[2]-2

输出 [0,4,0,0,0]

但是真是不建议在一个复杂的语句中使用i++或++i,给自己增加难度不说,也增加的以后的维护成本;看似很炫的代码换来的是后人的诅咒 ... ...

你可能感兴趣的:(i++和++i的区别)