一個關於i++和++i的原理詳解,對字節碼不太熟悉的能夠先了解下字節碼相關知識,由於從字節碼角度更能理解二者的原理。bash
int i = 0, j = 0;
i = i++;
j =++ j;
System.out.println("args = [" + i + "]");
System.out.println("args = [" + j + "]");
輸出結果:
args = [0]
args = [1]
複製代碼
對於i++
,++i
可能你們的第一反應的理解是:前者先運算再自增賦值,後者先自增賦值在運算。那麼上面那個例子爲何會得出這個結果,下面查看其字節碼,輸出的我就忽略不展現了。post
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_1
5: iinc 1, 1
8: istore_1
9: iinc 2, 1
12: iload_2
13: istore_2
複製代碼
0 ~ 3行很容易理解,在局部變量保存i和j 分別設值爲0。注意看4 ~ 8和9 ~ 13,他們分別表明的是i=i++
和j=++j
。他們之間的差異就在於load
指令一個在自增指令`iinc``前,一個在後學習
這裏說一下iinc
指令,它是int類型的局部變量自增指令(將後者數據加到前者下標的int類型局部變量中)。能夠看到這個指令和下一條指令之間左邊的行號是少了兩行的,那是由於這個指令顯示的是一條,可是幹了三件事,讀取該值,自增長一,將自增後的值保存回局部變量。spa
下面開始分析,執行i=i++
操做時(4 ~ 8),首先iload_1
使局部變量i(0)
入棧,而後執行iinc
注意,執行完iinc
後局部變量表中的i是已經變成1了,iinc
並非吃乾飯的,可是前一條指令入棧的值沒變,仍是0,而後緊接着對i
作等號賦值操做的istore_1
指令將棧頂的0又保存回了局部變量1(i)中,因此局部變量表中的值變化是:0 ~ 1 ~ 0;3d
不一樣的是,執行j=j++
操做時(9 ~ 13),先自增後局部變量表中j的值已經變成了1,而後執行=
號賦值操做,將++j
這一整個iinc
後的結果也就是局部變量表2中的值入棧(iload_2),而後賦值給j
(istore_2)。code
從上面的理解中能夠看到俗稱的:先運算在賦值和先賦值在運算
,其原理就在於iinc
指令是否先於局部變量的入棧賦值操做,下面再給幾個拓展例子看看。對象
例一:
int i = 0, j = 0;
i=i++ + i++;
j= ++j + j++;
例二:
int i = 0, j = 0;
j=i++ + i++;
例三:
int i = 0, j = 0;
j=i++ + ++i;
例四:
int i = 0, j = 0;
j=i++ + ++j;
複製代碼
上面我不列答案,你們能夠本身先猜想是多少,而後在看看本身分析的對不對。get
例一:第一個自增和前面的步驟同樣,入棧i
而後自增iinc
,可是第二個自增會從新把i從局部變量表入棧,此時i
通過前面自增已經爲1了,而後第二個自增後再賦值,結果就是i=0+1
且此時局部變量表中的i值爲2(這是等於號賦值前的值,賦值後又從新保存變爲1了)。 j
的運算我就簡要說一下了,和前面相似:先iinc
自增運算(差別),而後j
(1)入棧,而後出棧保存,再入棧j
(1)入棧,自增運算,而後相加。結果是j=1+1,且此時局部變量表中的j爲2,下面是字節碼:string
4: iload_1
5: iinc 1, 1
8: iload_1
9: iinc 1, 1
12: iadd
13: istore_1
14: iinc 2, 1
17: iload_2
18: iload_2
19: iinc 2, 1
22: iadd
23: istore_2
複製代碼
例二:例二和例一不一樣的是最後的賦值對象從自身變成了其餘人,因此這裏和例一i
運算解析是如出一轍的,只不過是最後括號內那句話中的賦值對象變成了j
,因此此時i=2,j=1
。class
例三:例三和例一j
運算解析也是相似的,一樣改變的是最後的賦值對象`,因此此時i=2,j=2
。
例四:例四雖然有點小不一樣,可是其原理仍是同樣的,先入棧i
再自增運算i++
,此時棧中的i
爲,0,變量表中的i
爲1;而後自增運算++j
,在入棧j
,相加得出結果再保存回變量表,因此結果就是j=0+1
,這裏得出的j=1
是相加運算得出的j=1
,並非自增指令得出的j=1
,好比此時i
爲4的話,結果就是i=5,j=5
。
4: iload_1
5: iinc 1, 1
8: iinc 2, 1
11: iload_2
12: iadd
13: istore_2
複製代碼
其實之前也看過i++和++i區別的文章,可是看過不就又忘了,最近在學習JVM相關知識,結果字節碼對這一原理有了更深的瞭解,起碼在腦子裏這個知識點的保質期會久一點。