溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解析Java虛擬機的Class文件

發(fā)布時間:2021-10-29 10:53:23 來源:億速云 閱讀:165 作者:柒染 欄目:編程語言

這篇文章給大家介紹如何解析Java虛擬機的Class文件,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

前面發(fā)了幾篇學習筆記,但是看這些東西總是感覺很"玄乎",來一篇實戰(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 //運行時常量池:用于存放編譯期生成的各種字面量和符號引用。    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()方法存儲至常量池  //該方法的參數(shù)為I,返回值為void  const #6 = Method       #41.#42;        //  java/io/PrintStream.println:(I)V  //類LearningClassFIle  const #7 = class        #43;    //  LearningClassFile  //構造函數(shù)  //該構造函數(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屬性只為***一個方法、實例類初始化方法或類初始化方法保存Java虛擬機指令及相關輔助信息  //簡而言之:保存方法編譯后的指令信息  const #24 = Asciz       Code;  //java源碼行號與編譯后的字節(jié)碼指令的對應表  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    //獲取靜態(tài)變量id2推送至棧頂     0:   getstatic       #4; //Field id2:I     //直接從常量池中取出id4的值5推送至棧頂     3:   iconst_5     //執(zhí)行相加操作     4:   iadd     //將計算結果推送至棧頂     5:   istore_0     //獲取靜態(tài)與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    //創(chuàng)建一個LearningClassFile對象,并將對象的引用推送至棧頂     0:   new     #7; //class LearningClassFile     //將對象的引用進行備份推送至棧頂     //使用原有的引用值調用實例方法,現(xiàn)在置于棧頂?shù)囊弥档奈恢脤⒈唤酉聛淼牟僮鞲采w。     3:   dup     //將構造函數(shù)中的參數(shù)1推送至棧頂     4:   iconst_1     5:   iconst_2     //執(zhí)行構造方法     6:   invokespecial   #8; //Method "<init>":(II)V     //將棧頂引用型數(shù)值存入第二個本地變量     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     //調用靜態(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)實例常量和類常量的區(qū)別

(2)初識方式不同:從class字節(jié)碼來看final修飾的變量會出現(xiàn)在每個構造方法中進行一次初始化;static final類型的變量必須在定義的時候進行初始化。 理解"編譯期可知,運行期不變": 編譯器可確定調用方法的版本,符合這個標準的方法主要有兩種:私有方法,靜態(tài)方法。

詳情請看:深入理解JVM讀書筆記--字節(jié)碼執(zhí)行引擎。

2、final變量和static final變量的區(qū)別:

(1)實例常量和類常量的區(qū)別

(2)初始化方式不同:從class字節(jié)碼來看final修飾的變量會出現(xiàn)在每個構造方法中進行一次初始化;static final類型的變量必須在定義的時候進行初始化。

3、理解"編譯期可知,運行期不變":

編譯器可確定調用方法的版本,符合這個標準的方法主要有兩種:私有方法,靜態(tài)方法。

關于如何解析Java虛擬機的Class文件就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI