助力软件开发企业降本增效 PHP / java源码系统,只需一次付费,代码终身使用! 广告
# i++和++i的区别 ```java int i = 1; int j1 = i++; // 先将i的原始值(1)赋值给变量j1(1),然后i变量的值加1 int j1 = ++i; // 先将i变量的值加1,然后将i的当前值(2)赋值给变量j1(2) ``` # 实现原理 源代码如下: ```java public class Test { public void testIPlus() { int i = 0; int j = i++; } public void testPlusI() { int i = 0; int j = ++i; } } ``` 经`javap`反编译后查看字节码如下: ```java { public Test(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public void testIPlus(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=3, args_size=1 0: iconst_0 // 生成整数0 1: istore_1 // 将整数0赋值给1号存储单元(即变量i) 2: iload_1 // 将1号存储单元的值加载到数据栈(此时 i=0,栈顶值为0) 3: iinc 1, 1 // 1号存储单元的值+1(此时 i=1) 6: istore_2 // 将数据栈顶的值(0)取出来赋值给2号存储单元(即变量j,此时i=1,j=0) 7: return // 返回时:i=1,j=0 LineNumberTable: line 4: 0 line 5: 2 line 6: 7 public void testPlusI(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=3, args_size=1 0: iconst_0 // 生成整数0 1: istore_1 // 将整数0赋值给1号存储单元(即变量i) 2: iinc 1, 1 // 1号存储单元的值+1(此时 i=1) 5: iload_1 // 将1号存储单元的值加载到数据栈(此时 i=1,栈顶值为1) 6: istore_2 // 将数据栈顶的值(1)取出来赋值给2号存储单元(即变量j,此时i=1,j=1) 7: return // 返回时:i=1,j=1 LineNumberTable: line 9: 0 line 10: 2 line 11: 7 } ``` 可以看到,区别在于第三步和第四部的顺序问题: * i++先执行`iload_1`,再执行`iinc`,也就是先将1号存储单元的值加载到数据栈,再将1号存储单元的值+1 * ++i先执行`iinc`,再执行`iload_1`,也就先将1号存储单元的值+1,再将1号存储单元的值加载到数据栈 执行完这两步后,将数据栈顶的值取出赋值给2号存储单元,也就是赋值给j。 # 实战 那么看看接下来的两个例子会输出什么呢 代码1: ```java public static void main(String[] args) { int a = 0; for (int i = 0; i < 99; i++) { a = a++; } System.out.print(a); } ``` 代码2: ```java public static void main(String[] args) { int a = 0; for (int i = 0; i < 99; i++) { a = ++a; } System.out.print(a); } ``` 在代码`a = a++`处IDE会提示`The value changed at 'a++' is never used `,也就是说a加1后的值从来没有被使用到。 那么我们来看看什么两个代码片段的执行结果: 代码1: ```plain 0 Process finished with exit code 0 ``` 代码2: ```plain 99 Process finished with exit code 0 ``` ***** 接下来我们从字节码角度看看为什么会这样,编写一个简单的代码片段: ```java int i = 0; i = i++; System.out.println("i=" + i); // 输出 i=0 ``` 编译后查看字节码如下: ```java 0: iconst_0 // 生成整数0 1: istore_1 // 将整数0赋值给1号存储单元(即变量i,i=0) 2: iload_1 // 将1号存储单元的值加载到数据栈(此时 i=0,栈顶值为0) 3: iinc 1, 1 // 1号存储单元的值+1(此时 i=1) 6: istore_1 // 将数据栈顶的值(0)取出来赋值给1号存储单元(即变量i,此时i=0) 7: getstatic #16 // 下面是打印到控制台指令 10: new #22 13: dup 14: ldc #24 16: invokespecial #26 19: iload_1 20: invokevirtual #29 23: invokevirtual #33 26: invokevirtual #37 29: return ``` 可以看到,对于代码`i = i++;`,在给1号存储单元赋值后,先将1号存储单元的值加载到数据栈,再将1号存储单元的值+1,然后再**将数据栈顶的值(0)取出来赋值给1号存储单元**。 因此在上面a++循环99次后,a的值依旧是0. # 总结 * i++会先使用i的值,也就是将i的值加载到数据栈,在给i加1,最后使用数据栈中的值。 * ++i会先将i的值加1,再将增加后的值加载到数据栈,再使用数据栈中的值。 # 参考 [深入理解Java中的i++、++i语句](https://blog.csdn.net/xialei199023/article/details/76383013)