一般认为前置++是先将变量的值加1,然后使用加1后的值参与运算;而后置++是先使用该值参与运算,然后再将该值加1。
先看第一个例子:
package test; public class Plus_Test01 { public static void main(String[] args) { int i = 100; i = i++; System.out.println(i); } }
猜猜结果是什么?
接着看第二个:
package test; public class Plus_Test02 { public static void main(String[] args) { int k = 100; while (true) { if (k++ > 100) { // System.out.println(k); break; } System.out.println(k); } } }
猜猜结果是什么?
实际上,不管是前置++,还是后置++,都是先将变量的值加1,然后才继续计算的。二者之间真正的区别是:前置++是将变量的值加1后,使用增值后的变量进行运算的,而后置++是首先将变量赋值给一个临时变量,接下来对变量的值加1,然后使用那个临时变量进行运算。
对于如下代码片段(前置++):
int i=1; int j=++i*5;
实际第二句上相当于:
i+=1; //将i加1 j=i*5; //将加1后的值与之进行计算, 此结果为:10
而对于如下代码片段(后置++):
int i=1; int j=i++*5;
第二句上相当于:
int temp=i; // 将i赋值给一个临时变量 i+=1; //将i加1 j=temp*5; //将临时变量与之计算, 此结果为:5
对于第一个例子,相当于:
int temp=i; i+=1; i=temp; //
所以结果应该为不变的,即100。
第一个例子的汇编代码为:
1 public static void main(java.lang.String[]); 2 descriptor: ([Ljava/lang/String;)V 3 flags: ACC_PUBLIC, ACC_STATIC 4 Code: 5 stack=2, locals=2, args_size=1 6 0: bipush 100 7 2: istore_1 8 3: iload_1 9 4: iinc 1, 1 //local var中第二个 加1 10 7: istore_1 //保存至local var 11 8: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream; 12 11: iload_1 //加载的参数为栈中的第二个,即仍然为100 13 12: invokevirtual #22 // Method java/io/PrintStream.println:(I)V 14 15: return
对于第二个例子,其实不难,结果是101,注意看一下流程,以后不能在犯这样的错误了。(流程为:首先比较temp=i,temp>100,,显然不成立,将i+=1,跳到syso那一句,打印的当然是101,再次循环同样有temp=i,temp>100,这次是成立的,然后i+=1,直接跳出循环,不会执行while里面的语句)。
第二个例子的汇编(只选取了main方法):
1 public static void main(java.lang.String[]); 2 descriptor: ([Ljava/lang/String;)V 3 flags: ACC_PUBLIC, ACC_STATIC 4 Code: 5 stack=2, locals=2, args_size=1 6 0: bipush 100 //100压栈 7 2: istore_1 //保存至第二个local var(第一个local var 是方法参数) 8 3: iload_1 //从第二个local var加载 9 4: iinc 1, 1 //给local var的2号位置的int值增加1(局部变量自增,结果仍然在local var中,操作数栈顶1不会变) 10 7: bipush 100 //100压栈 11 9: if_icmple 15 //比较操作数栈顶的两个int整型值,如果第一个小于或者等于第二个的话,然后跳转到15行 12 12: goto 25 //否则跳转到25行(即操作数栈顶1>操作数栈顶2) 13 15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 14 18: iload_1 // //从第一个个local var加载 15 19: invokevirtual #3 // Method java/io/PrintStream.println:(I)V //调用该方法 16 22: goto 3 //再次回跳至3,再次循环 17 25: return //退出
第三个例子:
1 package test; 2 3 public class Plus_Test03 { 4 5 static int proPlus() { 6 int i = 55; 7 int j = ++i; 8 return j; //56 9 } 10 11 static int postPlus() { 12 int i = 55; 13 int j = i++; 14 return j; //55 15 } 16 17 public static void main(String[] args) { 18 System.out.println(proPlus());//56 19 System.out.println(postPlus());//55 20 21 } 22 }
第三个例子的汇编:
static int proPlus(); descriptor: ()I flags: ACC_STATIC Code: stack=1, locals=2, args_size=0 0: bipush 55 //55压栈 2: istore_0 //将int型栈顶的存储至第一个local var 3: iinc 0, 1 //第一个local var加1 6: iload_0 //从local var加载 7: istore_1 //保存至第二个local var 8: iload_1 //栈顶为第二个local var 9: ireturnstatic int postPlus(); descriptor: ()I flags: ACC_STATIC Code: stack=1, locals=2, args_size=0 0: bipush 55 2: istore_0 3: iload_0 //加载至栈 4: iinc 0, 1 //第一个local var加1 7: istore_1 8: iload_1 9: ireturn
可见,前置++ 和后置++的不同点在于上面蓝色的部分,这两部分是反过来的。对于前置来说,会将local var中的数加1然后加载至栈中,而后置则是先从栈local var中加载至栈,然后将local var的加1,相当于留了一个备份。
结论:
一。前置、与后置++都是先将变量的值加1,而不是前置++先加1然后运算,而后置++先运算后加1。
二。从程序上说,后置++先将变量赋值给一个临时变量,然后将变量的值加1,接下来使用那个临时变量参与运算。
三。从指令上说,后置++在执行增值指令(iinc)前,先将变量的值压入栈,执行增值指令后,使用的是之前压入栈的值。