<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    中文JAVA技術(shù)平等自由協(xié)作創(chuàng)造

    Java專題文章博客和開源

    常用鏈接

    統(tǒng)計(jì)

    最新評(píng)論

    Java二進(jìn)制Class文件格式解析

      一、Java Class文件是什么

      《The JavaTM Virtual Machine Specification》(Second Edtion)中有表述:Java Class文件由8位字節(jié)流組成,所有的16位、32位和64位數(shù)據(jù)分別通過讀入2個(gè)、4個(gè)和8個(gè)字節(jié)來構(gòu)造,多字節(jié)數(shù)據(jù)總是按照Big-endian順序來存放,即高位字節(jié)在前(放在低地址)。每個(gè)Class文件都包含且僅包含一個(gè)Java類型(類或者接口)。

      或許,《The JavaTM Virtual Machine Specification》中的表述不夠明確,那么我們可以參考一下《Inside the Java Virtual Machine》(Second Edtion)中的表述:Java Class文件特指以。class為后綴名的Java虛擬機(jī)可裝載的文件。

      分析一下兩者的表述,我覺得都不夠全面、不夠明確。我是這么定義的:Java Class文件就是指符合特定格式的字節(jié)流組成的二進(jìn)制文件。這個(gè)特定的格式就是指第二節(jié)要討論的Class文件格式,亦即在《The JavaTM Virtual Machine Specification》中定義的Class文件格式。從另一個(gè)角度來說,這個(gè)特定格式就是指JVM能夠識(shí)別、能夠裝載的格式。為什么這么說呢?因?yàn)镴VM在裝載class文件時(shí),要進(jìn)行class文件驗(yàn)證,以保證裝載的class文件內(nèi)容符合正確的內(nèi)部結(jié)構(gòu)。這個(gè)內(nèi)部結(jié)構(gòu)指的就是這個(gè)特定格式,只要是符合這個(gè)特定格式的Class文件都是合法的、規(guī)范的Class文件,都是JVM能夠裝載的Class文件。如果覺得這樣的表述還是不夠明確,我只能建議你讀完這篇文章之后再回頭來理解看看了托福答案

      為了討論方便,在下文中將對(duì)這兩個(gè)參考資料做個(gè)簡(jiǎn)記:

      1)《The Java Virtual Machine Specification》(Second Edtion)簡(jiǎn)記為《JVM Spec》(2nded)。

      2)《Inside the Java Virtual Machine》(Second Edtion) 簡(jiǎn)記為《Inside JVM》(2nded)。

      二、Java Class文件的格式

      在講Class文件的格式之前,要介紹三個(gè)概念:

      1)數(shù)據(jù)類型:《JVM Spec》(2nded)中指出,Java Class文件的數(shù)據(jù)用自己定義的一個(gè)數(shù)據(jù)類型集來表示,即u1,u2,u4,分別用于表示一個(gè)無符號(hào)類型的、占1,2,4個(gè)字節(jié)的數(shù)據(jù)。在《Inside JVM》(2nded)一書中,作者把這個(gè)數(shù)據(jù)類型集稱之為Class文件的基本類型,本人覺得比較形象,便于理解。所以,在本文中,我們也用基本類型來表示Java Class文件的數(shù)據(jù)。

      2)表:根據(jù)《JVM Spec》(2nded)中的定義,表(table)由項(xiàng)(定義見3)組成,用于幾種Class文件結(jié)構(gòu)中。《JVM Spec》(2nded)中指出,Java Class文件格式用一個(gè)類似于C結(jié)構(gòu)的記號(hào)編寫的偽結(jié)構(gòu)來表示。這個(gè)偽結(jié)構(gòu)指的就是這里的表,例如下面的ClassFile表就是這種偽結(jié)構(gòu)的一個(gè)典型例子,下文中所有的表都是指這種偽結(jié)構(gòu)的表。表的大小是可變的,這是因?yàn)樗慕M成部分項(xiàng)是可變的。注意;這里的可變是針對(duì)Class層次而言的,即在不同的Class文件中該項(xiàng)的大小可能不一樣的,但是對(duì)于每一個(gè)具體的Class文件來說,這個(gè)項(xiàng)的大小又是一定的,因而這個(gè)表的大小也是一定的。那么,項(xiàng)為什么是可變的呢?請(qǐng)看下面的分析。

      3)項(xiàng):描述Java Class文件格式的結(jié)構(gòu)的內(nèi)容稱為項(xiàng)(items)。每個(gè)項(xiàng)都有自己的類型和名稱。項(xiàng)的類型可能是基本類型,也可能是一個(gè)表的名字,這種項(xiàng)都是一些數(shù)組項(xiàng)。數(shù)組項(xiàng)的每一個(gè)元素都是一個(gè)表,這個(gè)表同頂層的ClassFile表一樣,也都是一種偽結(jié)構(gòu),也都是由一些項(xiàng)構(gòu)成的,而且這些表不一定是同一種格式的,因此數(shù)組項(xiàng)也可以看作一個(gè)可變大小的結(jié)構(gòu)流J.這些表對(duì)于該數(shù)組項(xiàng)來說就是子項(xiàng),當(dāng)然子項(xiàng)可能還有子項(xiàng)(目前子項(xiàng)的深度最多就兩層)。項(xiàng)的名稱,沒有什么好說的,就是《JVM Spec》(2nded)中指定的一些名稱。另外,項(xiàng)也是有大小的,對(duì)于沒有子項(xiàng)的項(xiàng)來說,其大小是固定的;對(duì)于有子項(xiàng)的項(xiàng)來說,其大小是可變的。在一個(gè)具體的Class文件中,一個(gè)可變項(xiàng)(數(shù)組)的大小都會(huì)在其前一項(xiàng)中指定,為什么會(huì)是這樣的呢?因?yàn)椤禞VM Spec》(2nded)中就是這么定義的!在Class文件中,每個(gè)項(xiàng)按規(guī)范中定義好的順序存儲(chǔ)在Class文件中,相鄰的項(xiàng)之間沒有任何間隔,連續(xù)的項(xiàng)(數(shù)組)也是按順序存儲(chǔ),不進(jìn)行填充或者對(duì)齊,這樣可以使Class文件緊湊。

      好了,我想這三個(gè)概念我已經(jīng)解釋地比較清楚了,下面開始正式解析Class文件的格式。

      首先要來解析一下ClassFile表結(jié)構(gòu),這是《JVM Spec》(2nded)中定義的Class文件最外層的結(jié)構(gòu),換言之,就是Class文件的格式。

      ClassFile表結(jié)構(gòu)

      ClassFile {

      u4 magic;

      u2 minor_version;

      u2 major_version;

      u2 constant_pool_count;

      cp_info constant_pool[constant_pool_count-1];

      u2 access_flags;

      u2 this_Class;

      u2 super_Class;

      u2 interfaces_count;

      u2 interfaces[interfaces_count];

      u2 fields_count;

      field_info fields[fields_count];

      u2 methods_count;

      method_info methods[methods_count];

      u2 attributes_count;

      attribute_info attributes[attributes_count];

      }

      ClassFile表結(jié)構(gòu)由16個(gè)不同的項(xiàng)組成,其中的各項(xiàng)可以簡(jiǎn)要地分析如下:

      (1) magic

      每個(gè)Class文件的前4個(gè)字節(jié)被稱為它的魔數(shù)(magic number): 0xCAFEBABE.魔數(shù)的作用在于:可以輕松地分辨出Java Class文件和非Java Class文件。(如果一個(gè)文件不是以0xCAFEBABE開頭,它就肯定不是Java Class文件,因?yàn)樗环弦?guī)范J)。當(dāng)Java還稱為"Oak"的時(shí)候,這個(gè)魔數(shù)就已經(jīng)定下來了,它預(yù)示了Java這個(gè)名字的出現(xiàn)。魔數(shù)的來歷請(qǐng)大家自己查閱J

      (2) minor_version和major_version

      Class文件的下面4個(gè)字節(jié)包含了次、主版本號(hào)。通常只有給定主版本號(hào)和一系列次版本號(hào)后,Java虛擬機(jī)才能夠讀取Class文件。如果Class文件的版本號(hào)超出了Java虛擬機(jī)所能夠處理的有效范圍,Java虛擬機(jī)將不會(huì)處理該Class文件。例如J2SE5.0版本的虛擬機(jī)就不能執(zhí)行由J2SE6.0版本的編譯器編譯出來的Class文件。北美托福答案

      (3) constant_pool_count

      版本號(hào)后面的項(xiàng)是constant_pool_count即常量池計(jì)數(shù)項(xiàng),該項(xiàng)的值必須大于零,它給出該Class文件中常量池列表項(xiàng)的元素個(gè)數(shù),這個(gè)計(jì)數(shù)項(xiàng)包括了索引為0的constant_pool表項(xiàng),但是該表項(xiàng)不出現(xiàn)在Class文件的constant_pool列表中,因?yàn)樗槐A魹镴ava虛擬機(jī)內(nèi)部實(shí)現(xiàn)使用了,因此常量池列表的元素個(gè)數(shù)constant_pool_count-1,各個(gè)常量池表項(xiàng)的索引值分別為1到constant_pool_count-1.

      注:在這里,有幾個(gè)術(shù)語需要解釋一下,常量池即為constant_pool,常量池列表就是指constant_pool[ ],常量池表項(xiàng)即指常量池列表中的某一個(gè)具體的表項(xiàng)(元素)。這些常量池表項(xiàng)的可能類型如下述的cp_type表所示:

      cp_type

      入口類型 標(biāo)志值

      CONSTANT_Class 7

      CONSTANT_Fieldref 9

      CONSTANT_Methodref 10

      CONSTANT_InterfaceMethodref 11

      CONSTANT_String 8

      CONSTANT_Integer 3

      CONSTANT_Float 4

      CONSTANT_Long 5

      CONSTANT_Double 6

      CONSTANT_NameAndType 12

      CONSTANT_Utf8 1


      (4) constant_pool[ ]

      constant_pool_count項(xiàng)下面是constant_pool[ ]項(xiàng),即常量池列表,其中存儲(chǔ)了該ClassFile結(jié)構(gòu)及其子結(jié)構(gòu)中引用的各種常量,諸如文字字符串、final變量值、類名和方法名等等。在Java Class文件中,常量池表項(xiàng)是用一個(gè)cp_info結(jié)構(gòu)來描述的,常量池列表就是由constant_pool_count-1個(gè)連續(xù)的、可變長(zhǎng)度的cp_info表結(jié)構(gòu)構(gòu)成的constant_pool[ ]數(shù)組。為什么是constant_pool_count-1個(gè)constant_pool的原因,在上面已經(jīng)解釋了。每一個(gè)常量池表項(xiàng)都是一個(gè)變長(zhǎng)結(jié)構(gòu),其通常格式如下所示:

      cp_info

      cp_info表的tag項(xiàng)是一個(gè)無符號(hào)的byte類型值,它表明了cp_info表的類型和格式,具體的tag類型見上表。

      需要說明的是,cp_info只是一個(gè)抽象的概念,在Class文件中,它表現(xiàn)為一系列具體的、形如CONSTANT_Xxxx_info的constant_pool結(jié)構(gòu),其具體的格式由cp_info表的tag項(xiàng)(即第一個(gè)字節(jié))來確定。不同的cp_info表,其info[]項(xiàng)也是不一樣的,例如,CONSTANT_Class_info表的info[]項(xiàng)為"u2 name_index",而CONSTANT_Utf8_info表的info[]項(xiàng)為"u2 length; u1 bytes[length];",顯然,這兩個(gè)cp_info表是不一樣的,大小更是不一樣的,因而常量池表項(xiàng)的大小是可變的。由于常量池列表中的每個(gè)常量池表項(xiàng)的結(jié)構(gòu)是不一樣,因此常量池列表的大小也是可變的。在Class文件中,常量池列表項(xiàng)是一個(gè)可變長(zhǎng)度的結(jié)構(gòu)流。

      由cp_info表以及cp_type表我們可以知道,若cp_info表中tag(標(biāo)志)項(xiàng)的值為1時(shí),當(dāng)前的cp_info就是一個(gè)CONSTANT_Utf8_info表結(jié)構(gòu),若cp_info表中tag項(xiàng)的值為3,當(dāng)前的cp_info就是一個(gè)CONSTANT_Integer_info表結(jié)構(gòu),其它情況類推。這些表的結(jié)構(gòu)可以查閱《JVM Spec》(2nded)的第四章或者《Inside JVM》(2nded)的第六章。托福考前答案

      (5) access_flags

      緊接常量池后的兩個(gè)字節(jié)稱為access_flags,access_flags項(xiàng)描述了該Java類型的一些訪問標(biāo)志信息。例如,訪問標(biāo)志指明文件中定義的是類還是接口;訪問標(biāo)志還定義了在類或接口的聲明中,使用了哪些修飾符;類和接口是抽象的還是公共的等等。實(shí)際上,access_flags項(xiàng)的值是Java類型聲明中使用的訪問標(biāo)志符的掩碼(mask,這里掩碼指的是access_flags的值是所有訪問標(biāo)志值的總和,當(dāng)然,未被使用的標(biāo)志位在Class文件中都被設(shè)置為0.例如,若access_flags的值就是0x0001,就表示該Java類型的訪問標(biāo)志符是ACC_PUBLIC;若access_flags的值是0x0011,就表示該Java類型的訪問標(biāo)志符是ACC_PUBLIC和ACC_FINAL,因?yàn)橹挥羞@兩個(gè)標(biāo)志位的和才可能是0x0011;其它情況類推)。

      一個(gè)Java類型的所有access_flags標(biāo)志符如下表所示:

      access_flags

      標(biāo)志名稱 值 含義

      ACC_PUBLIC 0x0001 聲明為public,可以從它的包外訪問

      ACC_FINAL 0x0010 聲明為final,不允許有子類

      ACC_SUPER 0x0020 用invokespecial指令處理超類的調(diào)用

      ACC_INTERFACE 0x0200 表明是一個(gè)接口,而不是一個(gè)類

      ACC_ABSTRACT 0x0400 聲明為abstract,不能被實(shí)例化

      需要說明的是,這是針對(duì)一個(gè)Java類型的訪問標(biāo)志符列表,有的標(biāo)志符只有類可以使用,有的標(biāo)志符只有接口才可以使用,

      (6) this_class

      接下來的兩個(gè)字節(jié)為this_class項(xiàng),其值為一個(gè)對(duì)常量池表項(xiàng)的索引,即它指向一個(gè)常量池表項(xiàng),而且該常量池表項(xiàng)必須為CONSTANT_Class_info表的結(jié)構(gòu)。該表有一個(gè)name_index項(xiàng),該項(xiàng)將指向另一個(gè)常量池表項(xiàng),該表項(xiàng)包含了該類或者接口的完全限定名稱。

      (7) super_class

      緊接著this_class之后的兩個(gè)字節(jié)是super_class項(xiàng),該項(xiàng)必須是對(duì)常量池表項(xiàng)的一個(gè)有效索引或者值為0.如果super_class項(xiàng)的值為0,則該Class文件必須表示java.lang.Object類。如果super_class項(xiàng)的值不為0,則又分為兩種情況,若該Class文件表示一個(gè)類,則super_class項(xiàng)必須是對(duì)常量池中該類的超類的CONSTANT_Class_info表項(xiàng)的索引,這個(gè)超類和它的任何超類都不能是一個(gè)final類;若該Class文件表示一個(gè)接口,則super_class項(xiàng)必須是對(duì)常量池中表示java.lang.Object類的一個(gè)CONSTANT_Class_info表項(xiàng)的索引。美國托福答案

      (8) interfaces_count和interfaces[ ]

      緊接著super_class項(xiàng)后面的兩個(gè)字節(jié)是interfaces_count項(xiàng),此項(xiàng)表示由該類直接實(shí)現(xiàn)或者由該接口所擴(kuò)展的超接口的數(shù)量。

      緊接著interfaces_count項(xiàng)后面的是interfaces列表項(xiàng),它包含了由該類直接實(shí)現(xiàn)或者由該接口所擴(kuò)展的超接口的常量池索引,共計(jì)interfaces_count個(gè)索引。interfaces列表中的常量池索引按照該類型在源代碼中給定的從左到右的順序排列。

      (9) fields_count和fields[ ]

      接下來的是fields_count項(xiàng),該項(xiàng)的值給出了fields列表項(xiàng)中的field_info表結(jié)構(gòu)的數(shù)量,即表示了該Java類型聲明的類變量和實(shí)例變量的個(gè)數(shù)總和。

      fields列表項(xiàng)包含了在該Java類型中聲明的所有字段的完整描述。fields列表中的每個(gè)field_info表項(xiàng)都完整地表示了一個(gè)字段的信息,包括該字段的名稱、描述符和修飾符等。這些信息有的放在field_info表中,如修飾符;有的則放在field_info表所指向的常量池中,如名字和描述符。同前面的分析,fields列表項(xiàng)也是一個(gè)變長(zhǎng)結(jié)構(gòu)。

      需要說明的是,只有在該Java類型中聲明的字段才可能在fields列表中列出,fields列表中不包括從超類或者超接口中繼承而來的字段信息。

      (10) methods_count和methods[ ]

      在Class文件中,緊接著fields后面的是對(duì)在該Java類型中所聲明的方法的描述。首先是methods_count項(xiàng),它占兩個(gè)字節(jié)長(zhǎng)度,它的值表示對(duì)該Java類型中聲明的所有方法的總計(jì)數(shù)。methods_count項(xiàng)后面是methods列表項(xiàng),它由methods_count個(gè)連續(xù)的method_info表構(gòu)成。每個(gè)method_info表都包含了與一個(gè)方法相關(guān)的信息,如方法名、描述符(即方法的返回值及參數(shù)類型)以及一些其它信息。如果一個(gè)方法既非abstract也非native,那么該method_info表將包含該方法局部變量所需的棧空間長(zhǎng)度、為方法所捕獲的異常表、字節(jié)碼序列以及可選的行號(hào)表和局部變量表等信息。

      需要說明的是,只有在該Java類型中顯式定義的方法才可能在fields列表中列出,fields列表中不包括從超類或者超接口中繼承而來的方法信息。

      (11) attributes_count和attributes[ ]

      Class文件中最后的部分是屬性(attribute),它給出了在該Java類型中所定義的屬性的基本信息。首先是attributes_count項(xiàng),它占兩個(gè)字節(jié)長(zhǎng)度,它的值表示在后續(xù)的attributes列表中的attributes_info表的總個(gè)數(shù)。每個(gè)attributes_info表的第一項(xiàng)都是對(duì)常量池中CONSTANT_Utf8_info表項(xiàng)的一個(gè)索引,該表給出了此屬性的名稱。托福改分

      需要說明的是,屬性有很多種,在Class文件中的很多地方都出現(xiàn)了屬性這一項(xiàng),在頂層ClassFile表中有attributes屬性項(xiàng),在field_info表中也有attributes屬性項(xiàng),在method_info中也有attributes屬性項(xiàng),但是它們各有各的功能,詳見上述分析。在《JVM Spec》(2nded)中,為ClassFile表結(jié)構(gòu)的attributes列表項(xiàng)定義的唯一屬性是SourceFile屬性,為field_info表結(jié)構(gòu)的attributes列表項(xiàng)定義的唯一屬性是ConstantValue屬性,為method_info表結(jié)構(gòu)的attributes列表項(xiàng)定義的屬性是Code屬性和Exceptions屬性。

      總而言之,Class文件格式是一個(gè)規(guī)范性的格式。這個(gè)規(guī)范指的就是,上面提到的這些表結(jié)構(gòu)本身的規(guī)范性,以及這些表結(jié)構(gòu)之間的包含關(guān)系的規(guī)范性。實(shí)際上,《JVM Spec》(2nded)中就是通過表和項(xiàng)這兩個(gè)概念來組織Class文件的格式的。首先,ClassFile表就是Class文件最外層的結(jié)構(gòu),換言之,這就是Class文件的格式。其次,ClassFile表又是一些項(xiàng)組成的,這些項(xiàng)的內(nèi)容都要符合《JVM Spec》(2nded)中定義的規(guī)范,具體來說,若這個(gè)項(xiàng)的類型是基本類型,該項(xiàng)的值要符合規(guī)范,例如magic項(xiàng)一定要是0xCAFEBABE,access_flags項(xiàng)的值一定要是有效的標(biāo)志值等等;若這個(gè)項(xiàng)的類型是一個(gè)表名,即該項(xiàng)是一個(gè)數(shù)組項(xiàng),那么該數(shù)組項(xiàng)列表中的每一個(gè)表項(xiàng)都要是一個(gè)合法的、規(guī)范的表,不能是一個(gè)規(guī)范中沒有定義的新表,這就是包含關(guān)系的規(guī)范性,同樣,列表項(xiàng)中的每個(gè)表項(xiàng)本身也都要是符合其規(guī)范定義的表項(xiàng),例如常量池列表中的某個(gè)CONSTANT_Class_info表的name_index項(xiàng)不是對(duì)一個(gè)CONSTANT_Utf8_info表結(jié)構(gòu)的索引,那么這個(gè)常量池的表項(xiàng)就不是一個(gè)合法的表項(xiàng),因而這個(gè)常量池列表項(xiàng)就是不符合規(guī)范的,因而整個(gè)文件就是不符合規(guī)范的。

     

    posted on 2013-10-22 15:08 好不容易 閱讀(183) 評(píng)論(0)  編輯  收藏


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    PK10開獎(jiǎng) PK10開獎(jiǎng)
    主站蜘蛛池模板: 国产亚洲欧美在线观看| 亚洲国产最大av| 免费人妻精品一区二区三区| 成年轻人网站色免费看| 亚洲欧洲日本在线观看| 拍拍拍又黄又爽无挡视频免费| 亚洲a级片在线观看| 免费人成在线视频| 亚洲色偷偷综合亚洲AV伊人蜜桃| 三年片在线观看免费观看高清电影| 久久狠狠爱亚洲综合影院| 黄瓜视频高清在线看免费下载| 欧美日韩亚洲精品| xvideos亚洲永久网址| 国产免费AV片在线观看播放| 中文字幕亚洲一区| 免费播放在线日本感人片| 国产av天堂亚洲国产av天堂| 69影院毛片免费观看视频在线| 中文字幕亚洲综合久久综合 | 亚洲午夜电影在线观看| 午夜国产精品免费观看| 亚洲AV无码成人网站在线观看 | 久久久99精品免费观看| 久久亚洲AV无码精品色午夜 | 午夜宅男在线永久免费观看网| 国产成人精品日本亚洲专区6| 日韩午夜免费视频| 国产精品一区二区三区免费| 久久久久久影院久久久久免费精品国产小说| 亚洲va在线va天堂va四虎| 人禽杂交18禁网站免费| 日本一区二区在线免费观看 | 女人裸身j部免费视频无遮挡| 亚洲国产精品无码中文字| 一本无码人妻在中文字幕免费| 羞羞视频在线观看免费| 亚洲精品国产免费| 亚洲精品老司机在线观看| 久久国产免费观看精品3| 精品国产日韩亚洲一区91 |