i++與++i的區別
在說i++與++i的區別之前,我們不妨來看一下下面這幾行代碼:
這裏有四個問題,分別輸出的結果是什麼?
/**
* 程序員面試過程中,常見的 i++ 與 ++i 的區別,這裏需要從java的字節碼文件進行分析
*/
public void add(){
//第一類問題
int i1 = 10;
i1++;
System.out.println(i1);
int i2 = 10;
++i2;
System.out.println(i2);
//第二類問題
int i3 = 10;
int i4 = i3++;
System.out.println(i4);
int i5 = 10;
int i6 = ++i5;
System.out.println(i6);
//第三類問題
int i7 = 10;
i7 = i7++;
System.out.println(i7);
int i8 = 10;
i8 = ++i8;
System.out.println(i8);
//第四類問題:重點,易錯
int i9 = 10;
int i10 = i9++ + ++i9;
System.out.println(i10);
}
對於大多數人來說,前三個問題的輸出都不成問題。關鍵在於最後一個問題,很多人可能沒見過。
第一,二類問題分析
相信大家都知道,第一類問題的輸出都是11,結果相同。因此很好理解。第二類問題也很好理解,輸出的結果是10,11.
這裏給大家解釋一下,在運算中:
i++ :先引用後增加
++i :先增加後引用
即
i++ :先在i所在的表達式中使用i的當前值,後讓i加1
++i :讓i先加1,然後在i所在的表達式中使用i的新值
也就是說:
在 int i4 = i3++;這個表達式中,先執行 i4 = i3,把i3的值賦給i4,之後i3纔會進行+1操作。
在 int i6 = ++i5;這個表達式中,先執行 i3+1操作,之後在進行把i3的值賦給i4的操作。
第三類問題分析
可能有的人在回答這個問題時,就會不小心掉坑裏哦。我猜一下,有的人會說答案是11,11.
其實細心的人就會發現,第三類問題的答案和第二類的沒區別,答案依舊是10,11.
我們來分析一下,爲什麼結果還是一樣的呢。我們知道,i++與++i的區別就是一個先引用後增加,一個先增加後引用。如果你理解了這句話,這第三類問題就不攻自破了。他其實就是第二類問題的變形。
只不過不同的是,它把自身作爲值的傳遞和存儲對象了。會給我們造成一種錯覺。
下面我從java字節碼的角度帶大家分析一下這個問題:(此處涉及jvm的知識,希望大家集中注意力)
首先,我將這個程序預編譯成class類:
下面就是生成的class文件,此處被idea反編譯回來了!
public void add() {
int i1 = 10;
int i1 = i1 + 1;
System.out.println(i1);
int i2 = 10;
int i2 = i2 + 1;
System.out.println(i2);
int i3 = 10;
int var12 = i3 + 1;
System.out.println(i3);
int i5 = 10;
int i5 = i5 + 1;
System.out.println(i5);
int i7 = 10;
int var14 = i7 + 1;
System.out.println(i7);
int i8 = 10;
int i8 = i8 + 1;
System.out.println(i8);
int i9 = 10;
int i9 = i9 + 1;
++i9;
int i10 = i9 + i9;
System.out.println(i10);
}
其實從這裏,我們就可以看出一些頭緒。
大家注意看這裏:
此處就已經證實我之前說的,由於i++會先傳值,在自增。所以i7會被先傳值,而+1的值會被賦給一個新的臨時變量存儲起來。
而++i則會先自增,再傳值,所以編譯成class文件後,先自+1,後重新賦值回i8.
從而得到10,11這兩個結果!
想要自己動手嘗試的小夥伴,記得先將程序編譯一下,快捷鍵是ctrl+shift+F9。然後再打開如下如所示位置即可查看被編譯的class文件.
因此這裏我就不用往下分析了。
第四類問題(重難點)
想必很多小夥伴都不明白這一題輸出的答案爲什麼是22,爲什麼不是21?心裏肯定在想出題還能這樣出!
答案馬上揭曉。
首先,我們需要了解一個知識點。大家都聽說過java程序要想運行起來,必須得在特定的java環境中。那麼,這個環境中就由一個叫JVM的虛擬機來進行java程序的一切操作和管理。
在jvm中,虛擬機棧會對方法中的變量和操作進行處理。在虛擬機棧中,有一個局部變量表和操作數棧,他們兩個相互配合,完成一個方法的變量賦值,四則運算!
說到這裏,估計有的人已經有點懵了。那我就先上結果把!
結論:在進行表達式運算時,都是自右向左依次壓入棧中
因此,此處的 int i10 = i9++ + ++i9; 相當於先進行 ++i9,在進行 i10 = i9++的操作。
所以,此處的表達式就相當於
i9 = i9 + 1;
i10 = i9+i9;
i9 = i9 + 1;
也就是下圖的class文件所表示的這樣!
其實這裏的分析只是取巧,真正的分析因該是對他的字節碼進行分析。
先附上它的字節碼:
0 bipush 10
2 istore_0
3 iinc 0 by 1
6 getstatic #3 <java/lang/System.out>
9 iload_0
10 invokevirtual #4 <java/io/PrintStream.println>
13 bipush 10
15 istore_1
16 iinc 1 by 1
19 getstatic #3 <java/lang/System.out>
22 iload_1
23 invokevirtual #4 <java/io/PrintStream.println>
26 bipush 10
28 istore_2
29 iload_2
30 iinc 2 by 1
33 istore_3
34 getstatic #3 <java/lang/System.out>
37 iload_3
38 invokevirtual #4 <java/io/PrintStream.println>
41 bipush 10
43 istore 4
45 iinc 4 by 1
48 iload 4
50 istore 5
52 getstatic #3 <java/lang/System.out>
55 iload 5
57 invokevirtual #4 <java/io/PrintStream.println>
60 bipush 10
62 istore 6
64 iload 6
66 iinc 6 by 1
69 istore 6
71 getstatic #3 <java/lang/System.out>
74 iload 6
76 invokevirtual #4 <java/io/PrintStream.println>
79 bipush 10
81 istore 7
83 iinc 7 by 1
86 iload 7
88 istore 7
90 getstatic #3 <java/lang/System.out>
93 iload 7
95 invokevirtual #4 <java/io/PrintStream.println>
98 bipush 10
100 istore 8
102 iload 8
104 iinc 8 by 1
107 iinc 8 by 1
110 iload 8
112 iadd
113 istore 9
115 getstatic #3 <java/lang/System.out>
118 iload 9
120 invokevirtual #4 <java/io/PrintStream.println>
123 return
上面就是此程序的字節碼文件!
爲了便於大家理解,我在這裏引用尚硅谷的宋紅康老師的一張圖大致表示一下:(此處的圖並不匹配本程序,只是讓大家看一下結構)
先解釋一下馬上要用到的幾個操作:
- bipush 10 :指將10壓入操作數棧中
- istore 0 : 指將操作數棧中壓入的10出棧,並存入局部變量表中的0號地址
- iinc 0 by 1 :指當前值+1操作
- iload_0 : 指將局部變量表中0號地址的值取出,存入棧中
下面我們要看得是問題四得那一部分指令:
98 bipush 10
100 istore 8
102 iload 8
104 iinc 8 by 1
107 iinc 8 by 1
110 iload 8
112 iadd
113 istore 9
115 getstatic #3 <java/lang/System.out>
118 iload 9
120 invokevirtual #4 <java/io/PrintStream.println>
下面是大致執行過程:
由於操作得指令比較多,所以博主偷了個懶,把有些指令合併成一張圖表示了。希望大家見諒!
以上就是從字節碼文件解釋爲啥輸出結果是22,而不是21了。
如果對字節碼不理解的,建議就記住一個結論:
表達式運算,先從右開始。因此從右自左入棧!i++ :先引用後增加
++i :先增加後引用。
博主後記:
希望看到此篇博文的小夥伴,如果發現有什麼不對的地方,歡迎在下方留言指正!博主一定虛心接受並改正!大家一起共同進步。如果對你有所幫助,可以給博主一個贊👍。