深入java虛擬機器–Class檔案執行個體解析

來源:互聯網
上載者:User

  前面發了幾篇學習筆記,但是看這些東西總是感覺很"玄乎",來一篇實戰的東西來揭一下"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繼承的預設構造方法//觀察該方法的特徵:無參,傳回型別voidconst #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:Iconst #3 = Field        #7.#37; //  LearningClassFile.id1:Iconst #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/PrintStream;//將PrintStream的Println()方法儲存至常量池//該方法的參數為I,傳回值為voidconst #6 = Method       #41.#42;        //  java/io/PrintStream.println:(I)V//類LearningClassFIleconst #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類型的參數,傳回型別為voidconst #9 = Method       #7.#45; //  LearningClassFile.addPub:(II)Vconst #10 = Method      #7.#46; //  LearningClassFile.addPri:(II)Vconst #11 = Method      #7.#47; //  LearningClassFile.addSta:()Vconst #12 = Method      #7.#48; //  LearningClassFile.addFinal:(II)Vconst #13 = class       #49;    //  java/lang/Objectconst #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>":()Vconst #36 = NameAndType #17:#15;//  id3:Iconst #37 = NameAndType #14:#15;//  id1:Iconst #38 = NameAndType #16:#15;//  id2:Iconst #39 = class       #50;    //  java/lang/Systemconst #40 = NameAndType #51:#52;//  out:Ljava/io/PrintStream;const #41 = class       #53;    //  java/io/PrintStreamconst #42 = NameAndType #54:#55;//  println:(I)Vconst #43 = Asciz       LearningClassFile;const #44 = NameAndType #22:#26;//  "<init>":(II)Vconst #45 = NameAndType #27:#26;//  addPub:(II)Vconst #46 = NameAndType #28:#26;//  addPri:(II)Vconst #47 = NameAndType #29:#23;//  addSta:()Vconst #48 = NameAndType #30:#26;//  addFinal:(II)Vconst #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: 11public 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讀書筆記--位元組碼執行引擎。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.