国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

自己動手實現一個Java Class解析器

yanbingyun1990 / 2679人閱讀

摘要:在屬性中,和分別用于存儲字節碼長度和字節碼指令,每條指令即一個字節類型。在虛擬機執行時,通過讀取中的一個個字節碼,并將字節碼翻譯成相應的指令。另外,雖然是一個類型的值,但是實際上一個方法不允許超過條字節碼指令。

最近在寫一個私人項目,名字叫做ClassAnalyzerClassAnalyzer的目的是能讓我們對Java Class文件的設計與結構能夠有一個深入的理解。主體框架與基本功能已經完成,還有一些細節功能日后再增加。實際上JDK已經提供了命令行工具javap來反編譯Class文件,但本篇文章將闡明我實現解析器的思路。

Class文件

作為類或者接口信息的載體,每個Class文件都完整的定義了一個類。為了使Java程序可以“編寫一次,處處運行”,Java虛擬機規范對Class文件進行了嚴格的規定。構成Class文件的基本數據單位是字節,這些字節之間不存在任何分隔符,這使得整個Class文件中存儲的內容幾乎全部是程序運行的必要數據,單個字節無法表示的數據由多個連續的字節來表示。

根據Java虛擬機規范,Class文件采用一種類似于C語言結構體的偽結構來存儲數據,這種偽結構中只有兩種數據類型:無符號數和表。Java虛擬機規范定義了u1u2u4u8來分別表示1個字節、2個字節、4個字節和8個字節的無符號數,無符號數可以用來描述數字、索引引用、數量值或者是字符串。表是由多個無符號數或者其它表作為數據項構成的符合數據類型,表用于描述有層次關系的符合結構的數據,因此整個Class文件本質上就是一張表。在ClassAnalyzeru1u2u4u8分別對應于byteshortintlongClass文件被描述為如下Java類。

public class ClassFile {

    public U4 magic;                            // magic
    public U2 minorVersion;                     // minor_version
    public U2 majorVersion;                     // major_version
    public U2 constantPoolCount;                // constant_pool_count
    public ConstantPoolInfo[] cpInfo;           // cp_info
    public U2 accessFlags;                      // access_flags
    public U2 thisClass;                        // this_class
    public U2 superClass;                       // super_class
    public U2 interfacesCount;                  // interfaces_count
    public U2[] interfaces;                     // interfaces
    public U2 fieldsCount;                      // fields_count
    public FieldInfo[] fields;                  // fields
    public U2 methodsCount;                     // methods_count
    public MethodInfo[] methods;                // methods
    public U2 attributesCount;                  // attributes_count
    public BasicAttributeInfo[] attributes;     // attributes

}
如何解析

組成Class文件的各個數據項中,例如魔數、Class文件的版本等數據項、訪問標志、類索引、父類索引,它們在每個Class文件中都占用固定數量的字節,在解析時只需要讀取相應數量的字節。除此之外,需要靈活處理的主要包括4部分:常量池、字段表集合、方法表集合和屬性表集合。字段和方法都可以具備自己的屬性,Class本身也有相應的屬性,因此,在解析字段表集合和方法表集合的同時也包含了屬性表的解析。

常量池占據了Class文件很大一部分的數據,用于存儲所有的常量信息,包括數字和字符串常量、類名、接口名、字段名和方法名等。Java虛擬機規范定義了多種常量類型,每一種常量類型都有自己的結構。常量池本身是一個表,在解析時有幾點需要注意。

每個常量類型都通過一個u1類型的tag來標識。

表頭給出的常量池大小(constantPoolCount)比實際大1,例如,如果constantPoolCount等于47,那么常量池中有46項常量。

常量池的索引范圍從1開始,例如,如果constantPoolCount等于47,那么常量池的索引范圍為1~46。設計者將第0項空出來的目的是用于表達“不引用任何一個常量池項目”。

CONSTANT_Utf8_info型常量的結構中包含u1類型的tagu2類型的length和由lengthu1類型組成的bytes,這length字節的連續數據是一個使用MUTF-8Modified UTF-8)編碼的字符串。MUTF-8UTF-8并不兼容,主要區別有兩點:一是null字符會被編碼成2字節(0xC00x80);二是補充字符是按照UTF-16拆分為代理對分別編碼的,相關細節可以看這里(變種UTF-8)。

屬性表用于描述某些場景專有的信息,Class文件、字段表和方法表都有相應的屬性表集合。Java虛擬機規范定義了多種屬性,ClassAnalyzer目前實現了對常用屬性的解析。和常量類型的數據項不同,屬性并沒有一個tag來標識屬性的類型,但是每個屬性都包含有一個u2類型的attribute_name_indexattribute_name_index指向常量池中的一個CONSTANT_Utf8_info類型的常量,該常量包含著屬性的名稱。在解析屬性時,ClassAnalyzer正是通過attribute_name_index指向的常量對應的屬性名稱來得知屬性的類型。

字段表用于描述類或者接口中聲明的變量,字段包括類級變量以及實例級變量。字段表的結構包含一個u2類型的access_flags、一個u2類型的name_index、一個u2類型的descriptor_index、一個u2類型的attributes_countattributes_countattribute_info類型的attributes。我們已經介紹了屬性表的解析,attributes的解析方式與屬性表的解析方式一致。

Class的文件方法表采用了和字段表相同的存儲格式,只是access_flags對應的含義有所不同。方法表包含著一個重要的屬性:Code屬性。Code屬性存儲了Java代碼編譯成的字節碼指令,在ClassAnalyzer中,Code對應的Java類如下所示(僅列出了類屬性)。

public class Code extends BasicAttributeInfo {

    private short maxStack;
    private short maxLocals;
    private long codeLength;
    private byte[] code;
    private short exceptionTableLength;
    private ExceptionInfo[] exceptionTable;
    private short attributesCount;
    private BasicAttributeInfo[] attributes;
    ...

    private class ExceptionInfo {
        public short startPc;
        public short endPc;
        public short handlerPc;
        public short catchType;
          ...
    }
}

Code屬性中,codeLengthcode分別用于存儲字節碼長度和字節碼指令,每條指令即一個字節(u1類型)。在虛擬機執行時,通過讀取code中的一個個字節碼,并將字節碼翻譯成相應的指令。另外,雖然codeLength是一個u4類型的值,但是實際上一個方法不允許超過65535條字節碼指令。

代碼實現

ClassAnalyzer的源碼已放在了GitHub上。在ClassAnalyzer的README中,我以一個類的Class文件為例,對該Class文件的每個字節進行了分析,希望對大家的理解有所幫助。

參考

深入理解Java虛擬機

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/66642.html

相關文章

  • 深入理解虛擬機之虛擬機類加載機制

    摘要:最終形成可以被虛擬機最直接使用的類型的過程就是虛擬機的類加載機制。即重寫一個類加載器的方法驗證驗證是連接階段的第一步,這一階段的目的是為了確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見相關面試題總結 本節常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): 簡單說說類加載過...

    MadPecker 評論0 收藏0
  • Java 虛擬機類加載機制

    摘要:驗證驗證階段的主要目的是為了確保文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。不同的虛擬機對類驗證的實現可能會有所不同,但大致都會完成以下四個階段的驗證文件格式的驗證元數據的驗證字節碼驗證和符號引用驗證。 原文地址 虛擬機把描述類的數據從Class文件加載到內存,并對數據進行校驗,轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,Thisis ...

    Dionysus_go 評論0 收藏0
  • 自己動手在Spring-Boot上加強國際化功能

    摘要:還設置一個攔截器來攔截國際化語言的變化。修改啟動類攔截器現在我們再運行一下看看效果,看到每個鏈接都顯示的他們對應的國際化信息里的內容。 前言 公司將項目由Struts2轉到Springmvc了,由于公司業務是境外服務,所以對國際化功能需求很高。Struts2自帶的國際化功能相對Springmvc來說更加完善,不過spring很大的特性就是可定定制化性強,所以在公司項目移植的到Sprin...

    gecko23 評論0 收藏0
  • 如何實現一個Java Class字節解析(Golang版)

    摘要:在屬性中,和分別用于存儲字節碼長度和字節碼指令,每條指令即一個字節類型。在虛擬機執行時,通過讀取中的一個個字節碼,并將字節碼翻譯成相應的指令。另外,雖然是一個類型的值,但是實際上一個方法不允許超過條字節碼指令。 最近在寫一個私人項目,名字叫做SmallVM,SmallVM的目的在于通過實現一個輕量級的Java虛擬機,加深對Java虛擬機的認知和理解。在Java虛擬機加載類的過程中,需要...

    diabloneo 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<