您好,登錄后才能下訂單哦!
還是讓我們從一道面試題說起吧,代碼如下,你知道方法執行最后會輸出什么嗎?
public static void main(String[] args) {
int i = 0;
for (int j = 0; j < 50; j++) {
i = i++;
}
System.out.println(i);
}
不賣關子,最后輸出結果是0,而不是50,不知道跟你的認知是否一致。
直接上字節碼,讓我們從字節碼層面看看i++背后的邏輯。
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iload_1
11: iinc 1, 1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
先拋出這個方法局部變量表
0 1 2
args i j
pc 0~1兩個指令,為下標為1的局部變量賦值為0,也就是局部變量i
pc 2~3兩個指令,為下表為2的局部變量賦值為0,也就是局部變量j
pc 4~7三個指令,取局部變量j的值與50比較,如果j>=50,跳轉到pc=21的指令處,如果不滿足則順序往下執行
pc 10~14三個指令,是i=i++這行代碼編譯后的指令。在jvm中,局部變量表和操作數棧是兩個不同的存儲數據的內存區域。iload_1表示將局部變量表中下標為1的變量,也就是變量i的值復制一份,加載到操作數棧頂,innc 1,1 指令則將局部變量表中變量i的值加1再寫回局部變量表中變量i的位置,istore_1則將棧頂的數據覆蓋局部變量表中變量i的位置,所以執行完這3個命令后,變量i的值并沒有發生變化。用偽代碼來表示這三個指令的邏輯就是這樣
int stack_top = local_variable[1];//把下標為1的局部變量加載到棧頂
local_variable[1] = local_variable[1] + 1;//下標為1的局部變量自增1
local_variable[1] = stack_top;//用棧頂的值覆蓋下標為1的局部變量
pc 15指令iinc 2,1 將變量j自增1
pc 18指令goto 4,程序重新從pc=4的地方開始執行
pc 21~25三個指令,就是打印下標為1的局部變量,也就是打印變量i
所以,從pc10~14三個指令,可以看出變量i=i++這行代碼不會改變變量i的值,因此最后打印結果是0。
如果將 i=i++ 改成 i=++i,結果會是怎樣呢?
public static void main(String[] args) {
int i = 0;鄭州好的婦科醫院 http://www.zzkedayy.com/
for (int j = 0; j < 50; j++) {
i = ++i;
}
System.out.println(i);
}
輸出結果是50,還是直接看字節碼
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iinc 1, 1
13: iload_1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
除了指令10~14,對應的代碼就是 i=++i,其他部分跟上面的字節碼指令一樣,所以我們只看不一樣的部分。
pc 10 innc 1,1 這里先執行自增指令,將下標為1的局部變量i的值自增1
pc 13 iload_1 將下標為1的局部變量i的值加載到操作數棧頂
pc 14istore_1 將操作數棧頂的值覆蓋下標為1的局部變量i的值
用偽代碼來表示這段邏輯就是這樣
local_variable[1] = local_variable[1] + 1;//下標為1的局部變量自增1
int stack_top = local_variable[1];//把下標為1的局部變量加載到棧頂
local_variable[1] = stack_top;//用棧頂的值覆蓋下標為1的局部變量
所以,從pc10~14三個指令,可以看出變量 i=++i 這行代碼會使i的值增加1,因此最后打印結果是50。
與i++對應的指令不同的地方是,++i會先執行innc 1,1指令,這條指令會是i的值增加1,然后再參與計算。而i++會先將i的值保存到另外一個地方,然后再對i自增1,但是i=i++的賦值(也就是=)會用已保存的i的舊值覆蓋i的新值,所以i=i++,i的值并不會變。
總結:講解了i=i++和i=++i的字節碼底層原理。
不知道朋友你理解了沒有,試試這道題輸出結果是什么
int i = 0;
int result = i++ + ++i + i++;
System.out.println(result);
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。