淺談JVM 底層解析 i++和 ++i 區(qū)別
一、前言
如果只用普通的知識(shí)解釋i++和++i的話
i++ 先將i賦值再++
++i 先++再賦值
但是這簡(jiǎn)單的回答并不能入吸引面試官的眼球,如果用java字節(jié)碼指令分析則效果完全不同
二、代碼實(shí)現(xiàn)
public class OperandStackTest {
/**
程序員面試過(guò)程中, 常見(jiàn)的i++和++i 的區(qū)別
*/
public static void add(){
//第1類問(wèn)題:
int i1 = 10;
i1++;
System.out.println("i1 =" + i1);//11
int i2 = 10;
++i2;
System.out.println("i2 =" + i2);//11
//第2類問(wèn)題:
int i3 = 10;
int i4 = i3++;
System.out.println("i3 =" + i3);//11
System.out.println("i4 =" + i4);//10
int i5 = 10;
int i6 = ++i5;
System.out.println("i5 =" + i5);//11
System.out.println("i6 =" + i6);//11
//第3類問(wèn)題:
int i7 = 10;
i7 = i7++;
System.out.println("i7 =" + i7);//10
int i8 = 10;
i8 = ++i8;
System.out.println("i8 =" + i8);//11
//第4類問(wèn)題:
int i9 = 10;
int i10 = i9++ + ++i9;//10+12
System.out.println("i9 =" + i9);//12
System.out.println("i10 =" + i10);//22
}
public static void main(String[] args) {
add();
}
}
運(yùn)行結(jié)果
i1 = 11 i2 = 11 i3 = 11 i4 = 10 i5 = 11 i6 = 11 i7 = 10 i8 = 11 i9 = 12 i10 = 22
三、字節(jié)碼指令
通過(guò)javap -v out目錄下的class文件名 在終端運(yùn)行得到如下結(jié)果
public static void add();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=10, args_size=0
0: bipush 10
2: istore_0
3: iinc 0, 1
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: iload_0
10: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
13: bipush 10
15: istore_1
16: iinc 1, 1
19: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
26: bipush 10
28: istore_2
29: iload_2
30: iinc 2, 1
33: istore_3
34: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
37: iload_2
38: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
41: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
44: iload_3
45: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
48: bipush 10
50: istore 4
52: iinc 4, 1
55: iload 4
57: istore 5
59: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
62: iload 4
64: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
67: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
70: iload 5
72: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
75: bipush 10
77: istore 6
79: iload 6
81: iinc 6, 1
84: istore 6
86: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
89: iload 6
91: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
94: bipush 10
96: istore 7
98: iinc 7, 1
101: iload 7
103: istore 7
105: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
108: iload 7
110: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
113: bipush 10
115: istore 8
117: iload 8
119: iinc 8, 1
122: iinc 8, 1
125: iload 8
127: iadd
128: istore 9
130: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
133: iload 8
135: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
138: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
141: iload 9
143: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
146: return
四、字節(jié)碼解析
1. 第一類問(wèn)題
//第1類問(wèn)題:
int i1 = 10;
i1++;
System.out.println("i1 =" + i1);//11
int i2 = 10;
++i2;
System.out.println("i2 =" + i2);//11
對(duì)應(yīng)字節(jié)碼指令為
0: bipush 10 2: istore_0 3: iinc 0, 1 6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 9: iload_0 10: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 13: bipush 10 15: istore_1 16: iinc 1, 1 19: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 22: iload_1 23: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
先將i1的值為10入棧(bipush),然后將int類型的值從棧中存到局部變量表0的位置,然后執(zhí)行iinc將0位置的值+1,然后將局部變量表0位置的數(shù)入棧執(zhí)行輸出操作
所以i1的值為11
先將i2的值為10入棧(bipush),然后將int類型的值從棧中存到局部變量表1的位置,然后執(zhí)行iinc將1位置的值+1,然后將局部變量表1位置的數(shù)入棧執(zhí)行輸出操作
所以i2的值為11
由于沒(méi)有賦值操作,區(qū)別不大
2. 第二類問(wèn)題
//第2類問(wèn)題:
int i3 = 10;
int i4 = i3++;
System.out.println("i3 =" + i3);//11
System.out.println("i4 =" + i4);//10
int i5 = 10;
int i6 = ++i5;
System.out.println("i5 =" + i5);//11
System.out.println("i6 =" + i6);//11
對(duì)應(yīng)字節(jié)碼為
26: bipush 10 28: istore_2 29: iload_2 30: iinc 2, 1 33: istore_3 34: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 37: iload_2 38: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 41: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 44: iload_3 45: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 48: bipush 10 50: istore 4 52: iinc 4, 1 55: iload 4 57: istore 5 59: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 62: iload 4 64: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 67: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 70: iload 5 72: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
先將i3入棧存儲(chǔ)到局部變量表2的位置,然后將它入棧,執(zhí)行iinc將2位置的值加一,i4存儲(chǔ)到局部表量表3的位置
所以i3是11,i4還是10
將i5入棧存儲(chǔ)到局部變量表4的位置,由于是++i所以先iinc將4位置的值加一,然后將局部變量表4的值入棧,執(zhí)行賦值操作
所以i5、i6都是11
3. 第三類問(wèn)題
//第3類問(wèn)題:
int i7 = 10;
i7 = i7++;
System.out.println("i7 =" + i7);//10
int i8 = 10;
i8 = ++i8;
System.out.println("i8 =" + i8);//11
對(duì)應(yīng)字節(jié)碼
75: bipush 10 77: istore 6 79: iload 6 81: iinc 6, 1 84: istore 6 86: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 89: iload 6 91: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 94: bipush 10 96: istore 7 98: iinc 7, 1 101: iload 7 103: istore 7 105: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 108: iload 7 110: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
先將i7入棧,然后存到局部變量表6的位置,先把i6入棧,然后把6處的值加一,由于又將這個(gè)值存儲(chǔ)到局部變量表6處,所以產(chǎn)生覆蓋又把值變?yōu)?0
所以i7為10
而++i不會(huì)產(chǎn)生覆蓋先執(zhí)行加一然后再把值入棧,在賦值給局部變量表中
所以i8為11
4. 第四類問(wèn)題
//第4類問(wèn)題:
int i9 = 10;
int i10 = i9++ + ++i9;//10+12
System.out.println("i9 =" + i9);//12
System.out.println("i10 =" + i10);//22
對(duì)應(yīng)字節(jié)碼為
113: bipush 10 115: istore 8 117: iload 8 119: iinc 8, 1 122: iinc 8, 1 125: iload 8 127: iadd 128: istore 9 130: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 133: iload 8 135: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 138: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 141: iload 9 143: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 146: return
先將i9=10入棧,然后存在局部變量表8的位置
int i10 = i9++ + ++i9;
先iload將8位置的i9入棧然后執(zhí)行iinc將8處的i9加一,然后執(zhí)行++i9,在將8處的i9加一
此時(shí)i9=10+1+1為12
然后將8位置的i9入棧,執(zhí)行add將棧中的兩i9相加,得到的值存儲(chǔ)到局部變量表9的位置
所以i10=10+12(i9++后還是10,++i9后是12,因?yàn)閳?zhí)行了兩次iinc操作)
然后調(diào)用虛方法和靜態(tài)方法,在將9處的值入棧執(zhí)行輸出語(yǔ)句
到此這篇關(guān)于淺談JVM 底層解析 i++和 ++i 區(qū)別的文章就介紹到這了,更多相關(guān)JVM 底層解析 i++和 ++i 區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入剖析springBoot中的@Scheduled執(zhí)行原理
這篇文章主要介紹了springBoot中的@Scheduled執(zhí)行原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Android中幾種圖片特效的處理的實(shí)現(xiàn)方法
這篇文章主要介紹了 Android中幾種圖片特效的處理的實(shí)現(xiàn)方法的相關(guān)資料,這里有放大縮小圖片,獲得圓角圖片,獲得帶倒影圖片的幾種方法,需要的朋友可以參考下2017-08-08
Java實(shí)現(xiàn)Excel百萬(wàn)級(jí)數(shù)據(jù)導(dǎo)入功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)Excel百萬(wàn)級(jí)數(shù)據(jù)導(dǎo)入功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下2024-04-04
SpringBoot 3.0 新特性內(nèi)置聲明式HTTP客戶端實(shí)例詳解
聲明式 http 客戶端主旨是使得編寫(xiě) java http 客戶端更容易,為了貫徹這個(gè)理念,采用了通過(guò)處理注解來(lái)自動(dòng)生成請(qǐng)求的方式,本文給大家詳解介紹SpringBoot 聲明式HTTP客戶端相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2022-12-12
Maven一鍵部署Springboot到Docker倉(cāng)庫(kù)為自動(dòng)化做準(zhǔn)備(推薦)
這篇文章主要介紹了Maven一鍵部署Springboot到Docker倉(cāng)庫(kù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
淺談Hibernate對(duì)象狀態(tài)之間的神奇轉(zhuǎn)換
這篇文章主要介紹了淺談Hibernate對(duì)象狀態(tài)之間的神奇轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
JAVA使用JDBC連接oracle數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程
JDBC是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問(wèn),它由一組用Java語(yǔ)言編寫(xiě)的類和接口組成,下面這篇文章主要給大家介紹了關(guān)于JAVA使用JDBC連接oracle數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程,需要的朋友可以參考下2023-05-05
SpringBoot實(shí)現(xiàn)RabbitMQ監(jiān)聽(tīng)消息的四種方式
本文介紹了在Spring Boot中實(shí)現(xiàn)RabbitMQ監(jiān)聽(tīng)消息的幾種方式,包括使用@RabbitListener注解、MessageListenerAdapter、配置連接工廠和隊(duì)列等方式,感興趣的可以了解一下2024-07-07

