深入Java虛擬機(jī):Class文件實(shí)例解析
前面發(fā)了幾篇學(xué)習(xí)筆記,但是看這些東西總是感覺很"玄乎",來一篇實(shí)戰(zhàn)的東西來揭一下"JVM"的面紗,讓"SSH"時代的童鞋們來熟悉一下Java的"老祖爺"JVM。由于自己的水平有限,所以大家在看過程中發(fā)了什么問題,或者您有什么疑問請及時提出來,我及時解決。如果您有什么建議,那么更好大家一塊討論。
1、源碼文件
- public class LearningClassFile {
 - //普通變量
 - private int id1;
 - //靜態(tài)變量
 - private static int id2;
 - //常量
 - private final int id3 = 4;
 - //靜態(tài)常量
 - 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
 - //運(yùn)行時常量池:用于存放編譯期生成的各種字面量和符號引用。
 - Constant pool:
 - //從父類Object繼承的默認(rèn)構(gòu)造方法
 - //觀察該方法的特征:無參,返回類型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()方法存儲至常量池
 - //該方法的參數(shù)為I,返回值為void
 - const #6 = Method #41.#42; // java/io/PrintStream.println:(I)V
 - //類LearningClassFIle
 - const #7 = class #43; // LearningClassFile
 - //構(gòu)造函數(shù)
 - //該構(gòu)造函數(shù)需傳入兩個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類型的參數(shù),返回類型為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屬性只為***一個方法、實(shí)例類初始化方法或類初始化方法保存Java虛擬機(jī)指令及相關(guān)輔助信息
 - //簡而言之:保存方法編譯后的指令信息
 - const #24 = Asciz Code;
 - //java源碼行號與編譯后的字節(jié)碼指令的對應(yīng)表
 - 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;
 - {
 - //默認(rèn)構(gòu)造方法
 - 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類型的實(shí)例變量在每個構(gòu)造方法中都會進(jìn)行一次初始化。
 - 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類型的實(shí)例變量在每個構(gòu)造方法中都會進(jìn)行一次初始化。
 - 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
 - //獲取靜態(tài)變量id2推送至棧頂
 - 0: getstatic #4; //Field id2:I
 - //直接從常量池中取出id4的值5推送至棧頂
 - 3: iconst_5
 - //執(zhí)行相加操作
 - 4: iadd
 - //將計(jì)算結(jié)果推送至棧頂
 - 5: istore_0
 - //獲取靜態(tài)與out
 - 6: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
 - //取出計(jì)算結(jié)果
 - 9: iload_0
 - //調(diào)用println方法
 - 10: invokevirtual #6; //Method java/io/PrintStream.println:(I)V
 - //方法正常結(jié)束
 - 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
 - //創(chuàng)建一個LearningClassFile對象,并將對象的引用推送至棧頂
 - 0: new #7; //class LearningClassFile
 - //將對象的引用進(jìn)行備份推送至棧頂
 - //使用原有的引用值調(diào)用實(shí)例方法,現(xiàn)在置于棧頂?shù)囊弥档奈恢脤⒈唤酉聛淼牟僮鞲采w。
 - 3: dup
 - //將構(gòu)造函數(shù)中的參數(shù)1推送至棧頂
 - 4: iconst_1
 - 5: iconst_2
 - //執(zhí)行構(gòu)造方法
 - 6: invokespecial #8; //Method "<init>":(II)V
 - //將棧頂引用型數(shù)值存入第二個本地變量
 - 9: astore_1
 - 10: aload_1
 - 11: iconst_1
 - 12: iconst_2
 - //調(diào)用實(shí)例方法
 - 13: invokevirtual #9; //Method addPub:(II)V
 - 16: aload_1
 - 17: iconst_1
 - 18: iconst_2
 - 19: invokespecial #10; //Method addPri:(II)V
 - //調(diào)用靜態(tài)方法
 - 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變量的區(qū)別:
(1)實(shí)例常量和類常量的區(qū)別
(2)初識方式不同:從class字節(jié)碼來看final修飾的變量會出現(xiàn)在每個構(gòu)造方法中進(jìn)行一次初始化;static final類型的變量必須在定義的時候進(jìn)行初始化。 理解"編譯期可知,運(yùn)行期不變": 編譯器可確定調(diào)用方法的版本,符合這個標(biāo)準(zhǔn)的方法主要有兩種:私有方法,靜態(tài)方法。
詳情請看:深入理解JVM讀書筆記--字節(jié)碼執(zhí)行引擎。
2、final變量和static final變量的區(qū)別:
(1)實(shí)例常量和類常量的區(qū)別
(2)初始化方式不同:從class字節(jié)碼來看final修飾的變量會出現(xiàn)在每個構(gòu)造方法中進(jìn)行一次初始化;static final類型的變量必須在定義的時候進(jìn)行初始化。
3、理解"編譯期可知,運(yùn)行期不變":
編譯器可確定調(diào)用方法的版本,符合這個標(biāo)準(zhǔn)的方法主要有兩種:私有方法,靜態(tài)方法。
原文鏈接:http://www.cnblogs.com/focusj/archive/2012/03/05/2375357.html
【編輯推薦】















 
 
 






 
 
 
 