前面發了幾篇學習筆記,但是看這些東西總是感覺很"玄乎",來一篇實戰的東西來揭一下"JVM"的面紗,讓"SSH"時代的童鞋們來熟悉一下Java的"老祖爺"JVM。由於自己的水平有限,所以大家在看過程中發了什么問題,或者您有什么疑問請及時提出來,我及時解決。如果您有什么建議,那么更好大家一塊討論。
1. 源碼文件
public class LearningClassFile {
//普通變量
private int id1;
//靜態變量
private static int id2;
//常量
private final int id3 = 4;
//靜態常量
private static final int id4 = 5;
public LearningClassFile() {
}
public LearningClassFile(int id1, int id2) {
this.id1 = id1;
this.id2 = id2;
}
//使用public修飾的addPub方法
public void addPub(int a, int b) {
int result = a + b;
System.out.println(result);
}
//使用private修飾的addPri方法
private void addPri(int a, int b) {
int result = a + b;
System.out.println(result);
}
//使用static修飾的方法
public static void addSta() {
int result = id2 + id4;
System.out.println(result);
}
public static final void addFinal(int a, int b) {
int result = a + b;
System.out.println(result);
}
public static void main(String[] args) {
LearningClassFile lcf = new LearningClassFile(1, 2);
lcf.addPub(1, 2);
lcf.addPri(1, 2);
addSta();
addFinal(1, 2);
}
}
Class文件:
Compiled from "LearningClassFile.java"
public class LearningClassFile extends java.lang.Object
SourceFile: "LearningClassFile.java"
minor version: 0
major version: 50
//運行時常量池:用於存放編譯期生成的各種字面量和符號引用。
Constant pool:
//從父類Object繼承的默認構造方法
//觀察該方法的特征:無參,返回類型void
const #1 = Method #13.#35; // java/lang/Object."<init>":()V
//常量id3
//"#7.#36; // LearningClassFile.id3:I"
//#7:查找常量池中的類名LearningClassFile
//#36-->"const #36 = NameAndType #17:#15;// id3:I"
//NameAndType字面的意思是名稱和類型。即id3是變量的名稱,I表示id3是int類型
//綜合描述:LearningClassFile中的id3是int類型
const #2 = Field #7.#36; // LearningClassFile.id3:I
const #3 = Field #7.#37; // LearningClassFile.id1:I
const #4 = Field #7.#38; // LearningClassFile.id2:I
//將System的out存儲至常量池
//System類中out被public static final修飾的
//"public final static PrintStream out = nullPrintStream();"
//綜合描述:System類的out屬性是PrintStream類型
const #5 = Field #39.#40; // java/lang/System.out:Ljava/io/PrintS
tream;
//將PrintStream的Println()方法存儲至常量池
//該方法的參數為I,返回值為void
const #6 = Method #41.#42; // java/io/PrintStream.println:(I)V
//類LearningClassFIle
const #7 = class #43; // LearningClassFile
//構造函數
//該構造函數需傳入兩個int類型的變量
const #8 = Method #7.#44; // LearningClassFile."<init>":(II)V
//LearningClassFile的addPub方法
//#4-->"const #45 = NameAndType #27:#26;// addPub:(II)V"
//#27-->"const #27 = Asciz addPub;" 方法的名稱為:addPub
//#26-->"const #26 = Asciz (II)V;" 方法的類型:兩個int類型的參數,返回類型為void
const #9 = Method #7.#45; // LearningClassFile.addPub:(II)V
const #10 = Method #7.#46; // LearningClassFile.addPri:(II)V
const #11 = Method #7.#47; // LearningClassFile.addSta:()V
const #12 = Method #7.#48; // LearningClassFile.addFinal:(II)V
const #13 = class #49; // java/lang/Object
const #14 = Asciz id1;
const #15 = Asciz I;
const #16 = Asciz id2;
const #17 = Asciz id3;
//ConstantValue屬性表示一個常量字段的值
//即final修飾的屬性
const #18 = Asciz ConstantValue;
//對於final修飾的常量直接將類型和值存入常量池
const #19 = int 4;
const #20 = Asciz id4;
const #21 = int 5;
const #22 = Asciz <init>;
const #23 = Asciz ()V;
//Code屬性只為唯一一個方法、實例類初始化方法或類初始化方法保存Java虛擬機指令及相關輔助信息
//簡而言之:保存方法編譯后的指令信息
const #24 = Asciz Code;
//java源碼行號與編譯后的字節碼指令的對應表
const #25 = Asciz LineNumberTable;
const #26 = Asciz (II)V;
const #27 = Asciz addPub;
const #28 = Asciz addPri;
const #29 = Asciz addSta;
const #30 = Asciz addFinal;
const #31 = Asciz main;
const #32 = Asciz ([Ljava/lang/String;)V;
//java 源碼文件
const #33 = Asciz SourceFile;
const #34 = Asciz LearningClassFile.java;
const #35 = NameAndType #22:#23;// "<init>":()V
const #36 = NameAndType #17:#15;// id3:I
const #37 = NameAndType #14:#15;// id1:I
const #38 = NameAndType #16:#15;// id2:I
const #39 = class #50; // java/lang/System
const #40 = NameAndType #51:#52;// out:Ljava/io/PrintStream;
const #41 = class #53; // java/io/PrintStream
const #42 = NameAndType #54:#55;// println:(I)V
const #43 = Asciz LearningClassFile;
const #44 = NameAndType #22:#26;// "<init>":(II)V
const #45 = NameAndType #27:#26;// addPub:(II)V
const #46 = NameAndType #28:#26;// addPri:(II)V
const #47 = NameAndType #29:#23;// addSta:()V
const #48 = NameAndType #30:#26;// addFinal:(II)V
const #49 = Asciz java/lang/Object;
const #50 = Asciz java/lang/System;
const #51 = Asciz out;
const #52 = Asciz Ljava/io/PrintStream;;
const #53 = Asciz java/io/PrintStream;
const #54 = Asciz println;
const #55 = Asciz (I)V;
{
//默認構造方法
public LearningClassFile();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
//將id3的引用推送至棧頂
4: aload_0
//將4推送至棧頂
5: iconst_4
//將4賦值給id3
6: putfield #2; //Field id3:I
9: return
LineNumberTable:
line 11: 0 //public LearningClassFile() {
//對於final類型的實例變量在每個構造方法中都會進行一次初始化。
line 7: 4 // private final int id3 = 4;
line 12: 9 //}
public LearningClassFile(int, int);
Code:
Stack=2, Locals=3, Args_size=3
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_4
6: putfield #2; //Field id3:I
9: aload_0
10: iload_1
11: putfield #3; //Field id1:I
14: aload_0
15: pop
16: iload_2
17: putstatic #4; //Field id2:I
20: return
LineNumberTable:
line 14: 0 //public LearningClassFile(int id1, int id2) {
//對於final類型的實例變量在每個構造方法中都會進行一次初始化。
line 7: 4 // private final int id3 = 4;
line 15: 9 // this.id1 = id1;
line 16: 14 // this.id2 = id2;
line 17: 20 //}
public void addPub(int, int);
Code:
Stack=2, Locals=4, Args_size=3
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_3
8: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
11: return
LineNumberTable:
line 21: 0 // int result = a + b;
line 22: 4 // System.out.println(result);
line 23: 11 // }
public static void addSta();
Code:
Stack=2, Locals=1, Args_size=0
//獲取靜態變量id2推送至棧頂
0: getstatic #4; //Field id2:I
//直接從常量池中取出id4的值5推送至棧頂
3: iconst_5
//執行相加操作
4: iadd
//將計算結果推送至棧頂
5: istore_0
//獲取靜態與out
6: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
//取出計算結果
9: iload_0
//調用println方法
10: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
//方法正常結束
13: return
LineNumberTable:
line 33: 0 // int result = id2 + id4;
line 34: 6 // System.out.println(result);
line 35: 13 //}
public static final void addFinal(int, int);
Code:
Stack=2, Locals=3, Args_size=2
0: iload_0
1: iload_1
2: iadd
3: istore_2
4: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_2
8: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
11: return
LineNumberTable:
line 38: 0
line 39: 4
line 40: 11
public static void main(java.lang.String[]);
Code:
Stack=4, Locals=2, Args_size=1
//創建一個LearningClassFile對象,並將對象的引用推送至棧頂
0: new #7; //class LearningClassFile
//將對象的引用進行備份推送至棧頂
//使用原有的引用值調用實例方法,現在置於棧頂的引用值的位置將被接下來的操作覆蓋。
3: dup
//將構造函數中的參數1推送至棧頂
4: iconst_1
5: iconst_2
//執行構造方法
6: invokespecial #8; //Method "<init>":(II)V
//將棧頂引用型數值存入第二個本地變量
9: astore_1
10: aload_1
11: iconst_1
12: iconst_2
//調用實例方法
13: invokevirtual #9; //Method addPub:(II)V
16: aload_1
17: iconst_1
18: iconst_2
19: invokespecial #10; //Method addPri:(II)V
//調用靜態方法
22: invokestatic #11; //Method addSta:()V
25: iconst_1
26: iconst_2
27: invokestatic #12; //Method addFinal:(II)V
30: return
LineNumberTable:
line 43: 0 // LearningClassFile lcf = new LearningClassFile(1, 2);
line 44: 10 // lcf.addPub(1, 2);
line 45: 16 // lcf.addPri(1, 2);
line 46: 22 // addSta();
line 47: 25 // addFinal(1, 2);
line 48: 30 //}
}
final變量和static final變量的區別:
1. 實例常量和類常量的區別
2. 初識方式不同:從class字節碼來看final修飾的變量會出現在每個構造方法中進行一次初始化;static final類型的變量必須在定義的時候進行初始化。
理解"編譯期可知,運行期不變": 編譯器可確定調用方法的版本,符合這個標准的方法主要有兩種:私有方法,靜態方法。詳情請看:深入理解JVM讀書筆記--字節碼執行引擎。
2. final變量和static final變量的區別: (1) 實例常量和類常量的區別 (2) 初始化方式不同:從class字節碼來看final修飾的變量會出現在每個構造方法中進行一次初始化;static final類型的變量必須在定義的時候進行初始化。
3. 理解"編譯期可知,運行期不變": 編譯器可確定調用方法的版本,符合這個標准的方法主要有兩種:私有方法,靜態方法。詳情請看:深入理解JVM讀書筆記--字節碼執行引擎。
