Java位元組碼常量池深度剖析與位元組碼整體結構分解

來源:互聯網
上載者:User

標籤:logs   不同的   sig   mpi   table   from   targe   web   表示   

常量池深度剖析:

在上一次【https://www.cnblogs.com/webor2006/p/9416831.html】中已經將常量池分析到了2/3了,接著把剩下的分析完,先回顧一下我們編譯的源檔案為:

然後用javap -verbose查看一下編譯位元組碼的資訊,其中字串相關的如下:

而對應用Hex Fiend來查看字元碼的二進位檔案的位置如下:

另外在繼續分析之前再來回顧下常量的對應表,如下:

好下面開始,先來讀一個位元組來看一下是什麼類型的常量:

查表可以看到是屬於這個常量:

接著2個位元組表示字串的長度,所以往下數二個位元組:

長度為4,則下往下數4個位元組則為常量的內容:

用javap -verbose來確認一下是否也是它:

接下來繼續讀一個位元組:

又是同樣的常量類型,所以直接再讀二個位元組來看一下字串的長度是多少:

長度為3,則往後再數3個位元組:

看一下javap -verbose:

實際上"getA()I"就可以確認其方法名為getA,無參,並且傳回值為整型,就可以完全的對應的來源程式中的方法了。

接下來繼續往下,讀一個位元組:

同樣的類型,不多說,直接往下再看兩個位元組來決定字串的長度:

佔四個位元組,於是乎往後再數四個位元組:

對一下javap -verbose:

繼續往下,讀一個位元組:

再數2個位元組:

往下數四個位元組:

對應於javap -verbose:

而同樣的“setA(I)V”,表示方法名為setA,方法的參數為整型,無傳回值,這樣又可以定位到具體的唯一的方法了。

繼續往下:

往下數10個位元組:

對應javap -verbose:

代表源檔案,再往下讀:

長度為12,往下數12個位元組:

而這兩個資訊描述了當前位元組碼檔案是由哪個源檔案編譯出來的,所以這也是為啥在執行javap命令時有如下一個資訊:

繼續往下走:

此時不再是01類型的常量了,而是12,所以具體它代表什麼類型還得查表,如下:

其第二項表示名稱的索引,而第三項為描述的索引,所以往下讀4個位元組:

看一下javap -verbose所顯示的:

其中方法名稱為<init>表示是構造方法,而()V表示該構造方法不帶參數沒的傳回值,也就是預設構造方法。

接下來繼續:

又是同樣的常量,所以直接往後數四個位元組:

對應javap -verbose:

這個資訊表示成員變數a,如下:

繼續往下看:

字串常量,對它的分析已經了如指掌了,往後數兩個位元組來看下字串的長度:

長度為24,則往後數24個位元組:

對應javap -verbose:

表示類的全域限定名,注意反應到位元組碼檔案來說全域限定名都是以“/”分隔的,而不像我們看到的包名那樣以“.”分隔的,繼續往下:

再往下數兩個位元組:

16,則往下數16個位元組:

對應javap -verbose:

表示當前類的父類的完全限制名,到此,常量池就全部分析完了~所以總結一下,對於一個類常量池的大小是不定的,那JVM如何在字型碼檔案中來知道常量池在哪結束呢?首先字元碼能知道常量池的總大小,如下:

為24個,但是由於第一個為備用的,所以總常量池的大小為23,而每個常量第一個位元組都是什麼類型的常量,然後不同的常量其往下讀幾個位元組都是確定的,所以這樣就可以知道讀到哪常量池就結束了。

位元組碼整體結構分解:

上面已經將整個常量池都已經分析完了,那之後還有那麼多位元組:

對應javap -verbose:

Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest1.class  Last modified Aug 10, 2018; size 479 bytes  MD5 checksum 4616561f95c24d6b04ea48a360437b8d  Compiled from "MyTest1.java"public class com.jvm.bytecode.MyTest1  minor version: 0  major version: 52  flags: ACC_PUBLIC, ACC_SUPERConstant pool:   #1 = Methodref          #4.#20         // java/lang/Object."<init>":()V   #2 = Fieldref           #3.#21         // com/jvm/bytecode/MyTest1.a:I   #3 = Class              #22            // com/jvm/bytecode/MyTest1   #4 = Class              #23            // java/lang/Object   #5 = Utf8               a   #6 = Utf8               I   #7 = Utf8               <init>   #8 = Utf8               ()V   #9 = Utf8               Code  #10 = Utf8               LineNumberTable  #11 = Utf8               LocalVariableTable  #12 = Utf8               this  #13 = Utf8               Lcom/jvm/bytecode/MyTest1;  #14 = Utf8               getA  #15 = Utf8               ()I  #16 = Utf8               setA  #17 = Utf8               (I)V  #18 = Utf8               SourceFile  #19 = Utf8               MyTest1.java  #20 = NameAndType        #7:#8          // "<init>":()V  #21 = NameAndType        #5:#6          // a:I  #22 = Utf8               com/jvm/bytecode/MyTest1  #23 = Utf8               java/lang/Object{  public com.jvm.bytecode.MyTest1();    descriptor: ()V    flags: ACC_PUBLIC    Code:      stack=2, locals=1, args_size=1         0: aload_0         1: invokespecial #1                  // Method java/lang/Object."<init>":()V         4: aload_0         5: iconst_1         6: putfield      #2                  // Field a:I         9: return      LineNumberTable:        line 3: 0        line 4: 4      LocalVariableTable:        Start  Length  Slot  Name   Signature            0      10     0  this   Lcom/jvm/bytecode/MyTest1;  public int getA();    descriptor: ()I    flags: ACC_PUBLIC    Code:      stack=1, locals=1, args_size=1         0: aload_0         1: getfield      #2                  // Field a:I         4: ireturn      LineNumberTable:        line 7: 0      LocalVariableTable:        Start  Length  Slot  Name   Signature            0       5     0  this   Lcom/jvm/bytecode/MyTest1;  public void setA(int);    descriptor: (I)V    flags: ACC_PUBLIC    Code:      stack=2, locals=2, args_size=2         0: aload_0         1: iload_1         2: putfield      #2                  // Field a:I         5: return      LineNumberTable:        line 11: 0        line 12: 5      LocalVariableTable:        Start  Length  Slot  Name   Signature            0       6     0  this   Lcom/jvm/bytecode/MyTest1;            0       6     1     a   I}SourceFile: "MyTest1.java"

目前還分析不了,因為還缺少知識理論,所以先來補一補知識,先來對位元組碼的整體結構有一個瞭解,先來看張圖:

目前已經學習了前三個結構,如下:

接著來瞭解新的位元組結構,接下來是“Access Flags”,表示存取修飾詞:

如:public、public static、public abstract、private、protected等。 

接著往下表示當前類的名字,如下:

再往下表示父類的名字:

接下來表示介面相關的資訊:

其中可以發現一個細節:

父類的位元組數是確定的,而介面是不確實的,這也跟java的單繼承多實現的特性吻和。

繼續往下則是欄位相關的資訊:

接下來由是類的方法相關的一些資訊:

這個就比較複雜了,因為方法裡面有執行代碼,在未來會學習到。

最後則表示當前類的一些附加的屬性:

因為JVM在編譯時間會增加一些特定的一些屬性資訊。

Java位元組碼常量池深度剖析與位元組碼整體結構分解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.