博文前言:
前幾天在一個帖子中看到有這麼幾行代碼,覺得有點兒意思,結果差點兒想少了!
public class JvmTest{
public static void main(String [] args){
int j = 0;
for(int i = 0;i<10;i++){
j = (j++);
}
System.out.println(j);//0
}
}
這幾行代碼主要考察的是++i和i++的區別!主要用到的就是java虛擬機棧!
1.1 java虛擬機棧:
java虛擬機棧是線程私有的,他與線程的聲明週期同步。虛擬機棧描述的是java方法執行的內存模型,每個方法執行都會創建一個棧幀,棧幀主要包含局部變量表、操作數棧、動態連接、方法出口。
1.1.1 我們可以把上述代碼簡化然後使用javap命令進行反彙編
1)簡化後的代碼
public class JvmTest {
public static void main(String[] args) {
int i = 0;
int j = 0;
j = i++;
System.out.println(j);//0
}
}
2) 使用 javap -c JvmTest >> JvmTxt.txt
對JvmTest.class 進行反彙編,並生成到JvmTxt.txt文件
Compiled from "JvmTest.java"
public class JvmTest {
public JvmTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0 // iconst_0:將0壓棧
1: istore_1 // istore_1: 將0存入局部變量1,此時局部變量表中局部變量1爲i:操作數棧中的0出棧並賦值給i ,現在局部變量表中i =0
2: iconst_0 // iconst_0:將0壓棧
3: istore_2 // istore_2:將0存入局部變量2,此時局部變量表中局部變量1爲j:操作數棧中的0出棧並賦值給j,現在局部變量表中j =0
4: iload_1 // iload_1:從局部變量1中裝載0 ,將i的值壓棧到操作數棧
5: iinc 1, 1 // iinc 1, 1 :把常量1加到局部變量1(i)此時 i = 1
8: istore_2 // istore_2 將int類型值存入局部變量2:將0出棧,將並 0賦值給j,此時j = 0
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: iload_2 // iload_2 從局部變量2中裝載int類型值: 將局部變量表中j 的值0 壓棧,此時棧頂元素爲0
13: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
16: return
}
3)這裏面出現的幾個指令集的含義,其他指令集含義請自行百度
iconst_0 將int類型常量0壓入棧
istore_1 將int類型值存入局部變量1
iconst_0 將int類型常量0壓入棧
istore_2 將int類型值存入局部變量2
iload_1 從局部變量1中裝載int類型
iinc 把一個常量值加到一個int類型的局部變量上
getstatic 從類中獲取靜態字段
iload_2 從局部變量2中裝載int類型值
調度對象的實便方法:invokevirtual
經過如上分析我們可以明確得出程式最後輸出的值是0。
1.1.2 類比第一個案例
同樣的道理,第一個案例中儘管循環多次,但最後會重新將局部變量表中的j =0的值入棧,所以最後的輸出結果依舊是0 ,這個過程都是在java棧中的操作數棧中完成的
如下是jvm的內存結構