一般認為前置++是先將變量的值加1,然后使用加1后的值參與運算;而后置++是先使用該值參與運算,然后再將該值加1。
先看第一個例子:
1
2
3
4
5
6
7
8
|
package test; public class Plus_Test01 { public static void main(String[] args) { int i = 100 ; i = i++; System.out.println(i); } } |
猜猜結果是什么?
接著看第二個:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: bipush 100 2: istore_1 3: iload_1 4: iinc 1, 1 //local var中第二個 加1 7: istore_1 //保存至local var 8: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 //加載的參數為棧中的第二個,即仍然為100 12: invokevirtual #22 // Method java/io/PrintStream.println:(I)V 15: return |
對于第二個例子,其實不難,結果是101,注意看一下流程,以后不能在犯這樣的錯誤了。(流程為:首先比較temp=i,temp>100,,顯然不成立,將i+=1,跳到syso那一句,打印的當然是101,再次循環同樣有temp=i,temp>100,這次是成立的,然后i+=1,直接跳出循環,不會執行while里面的語句)。
第二個例子的匯編(只選取了main方法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack= 2 , locals= 2 , args_size= 1 0 : bipush 100 //100壓棧 2 : istore_1 //保存至第二個local var(第一個local var 是方法參數) 3 : iload_1 //從第二個local var加載 4 : iinc 1 , 1 //給local var的2號位置的int值增加1(局部變量自增,結果仍然在local var中,操作數棧頂1不會變) 7 : bipush 100 //100壓棧 9 : if_icmple 15 //比較操作數棧頂的兩個int整型值,如果第一個小于或者等于第二個的話,然后跳轉到15行 12 : goto 25 //否則跳轉到25行(即操作數棧頂1>操作數棧頂2) 15 : getstatic # 2 // Field java/lang/System.out:Ljava/io/PrintStream; 18 : iload_1 // //從第一個個local var加載 19 : invokevirtual # 3 // Method java/io/PrintStream.println:(I)V //調用該方法 22 : goto 3 //再次回跳至3,再次循環 25 : return //退出 |
第三個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package test; public class Plus_Test03 { static int proPlus() { int i = 55; int j = ++i; return j; //56 } static int postPlus() { int i = 55; int j = i++; return j; //55 } public static void main(String[] args) { System.out.println(proPlus()); //56 System.out.println(postPlus()); //55 } } |
第三個例子的匯編:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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中的數加1然后加載至棧中,而后置則是先從棧local var中加載至棧,然后將local var的加1,相當于留了一個備份。
結論:
一。前置、與后置++都是先將變量的值加1,而不是前置++先加1然后運算,而后置++先運算后加1。
二。從程序上說,后置++先將變量賦值給一個臨時變量,然后將變量的值加1,接下來使用那個臨時變量參與運算。
三。從指令上說,后置++在執行增值指令(iinc)前,先將變量的值壓入棧,執行增值指令后,使用的是之前壓入棧的值。
希望通過此文,徹底理解前置++和后置++的運算區別,謝謝大家對本站的支持!