讀《深入理解JVM》筆記之class文件結(jié)構(gòu)

Class文件是一組以8位字節(jié)為基礎(chǔ)單位的二進(jìn)制流迂曲,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格按照順序緊湊地排列在Class文件之中腌逢,中間沒有添加任何分隔符萨西,這使得整個(gè)Class文件中存儲(chǔ)的內(nèi)容幾乎全部是程序運(yùn)行的必要數(shù)據(jù)妄壶,沒有空隙存在霞扬。

數(shù)據(jù)結(jié)構(gòu)

class文件格式采用一種類似于C語言結(jié)構(gòu)體的偽結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù),這種偽結(jié)構(gòu)中只有兩種數(shù)據(jù)類型翼闹,

  • 無符號(hào)數(shù)斑鼻。基本數(shù)據(jù)類型猎荠,以u(píng)1坚弱、u2、u4关摇、u8分別代表1個(gè)字節(jié)荒叶、2個(gè)字節(jié)、4個(gè)字節(jié)输虱、8個(gè)字節(jié)的無符號(hào)數(shù)些楣。無符號(hào)數(shù)可以用來描述數(shù)字、索引引用悼瓮、數(shù)值戈毒、按照UTF-8編碼構(gòu)成字符串值
  • 表。復(fù)合結(jié)構(gòu)類型横堡。表可以由多個(gè)無符號(hào)數(shù)或者其他表構(gòu)成。整個(gè)class文件本質(zhì)上就是一張表冠桃。

NOTE:無論是無符號(hào)數(shù)還是表命贴,當(dāng)需要描述同一類型但數(shù)量不定的多個(gè)數(shù)據(jù)時(shí),經(jīng)常會(huì)使用一個(gè)前置的容量計(jì)數(shù)器加若干個(gè)連續(xù)的數(shù)據(jù)項(xiàng)的形式食听。

class文件組成
Figure1 class文件格式
  • 魔數(shù)
  • 次版本號(hào)
  • 主版本號(hào)
  • 常量池
    常量池中存放的內(nèi)容主要包括兩種類型胸蛛,字面量和符號(hào)引用。
    其中字面量包括字符串樱报、final常量等葬项;符號(hào)引用包括類和接口的全限定名、字段名稱和描述符迹蛤、方法名和描述符民珍。

常量池中的每一項(xiàng)常量都是一個(gè)表。共有14種類型的表盗飒。


Figure2 常量池的項(xiàng)目類型

可以看到常量池中涉及的項(xiàng)目類型分成了三大類型嚷量,字面量用的類型、符號(hào)引用用的類型逆趣、后三種CONSTANT_MethodHandle_info蝶溶、CONSTANT_MethodType_info、CONSTANT_InvokeDynamic_info是為了更好的支持動(dòng)態(tài)語言特性在JDK1.7添加的宣渗,其余11種是在JDK1.7之前就有抖所。

查看Figure 3梨州,可以得到一個(gè)共同點(diǎn):這些表的結(jié)構(gòu)的第一個(gè)字節(jié)存放類型標(biāo)記tag,作用顯而易見田轧,用來區(qū)分這些常量類型摊唇。
Figure3 14種常量池使用的表結(jié)構(gòu)
  • access_flags(訪問標(biāo)志)

    注意該訪問標(biāo)志是針對(duì)類或接口而言,與字段涯鲁、方法無關(guān)巷查。從圖中可以看出這些是經(jīng)常用來修飾類或者接口的修飾符。access_flags數(shù)據(jù)類型為u2抹腿,所以access_flags一共有16個(gè)標(biāo)記位可供使用(標(biāo)記則記為1岛请,否則為0)。當(dāng)前只定義了8個(gè)警绩,沒用到的置為0崇败。
    Figure4 類或接口訪問標(biāo)志
  • 類索引、父類索引肩祥、接口索引集合
    從class文件格式圖可以看出后室,類索引、父類索引混狠、接口索引類型都是u2岸霹。類索引確定該類或者接口的全限定名,父類索引確定該類的父類的全限定名将饺,因?yàn)镴ava語言不允許多重繼承贡避,所有父類索引值為1,且Java中除了Object類沒有父類外予弧,其他類都有父類刮吧,所以除Object類外,所有的Java類的父類索引不為0掖蛤。

  • 字段集合

    字段包括類級(jí)變量(即static修飾的靜態(tài)變量)以及實(shí)例級(jí)變量杀捻,不包括方法中聲明的局部變量。
    Figure5 字段表結(jié)構(gòu)

    看一下字段表的構(gòu)成蚓庭。access_flags是一個(gè)u2類型的項(xiàng)目致讥,它用來存放字段的修飾符,這些修飾符包括以下彪置,
    Figure6 字段方法標(biāo)記

之后是name_index拄踪、descriptor_index兩個(gè)索引值,name_index代表著字段的簡(jiǎn)單名稱拳魁,descriptor_index代表著字段的描述符惶桐。簡(jiǎn)單名稱很好理解,在使用Log的時(shí)候經(jīng)常需要一個(gè)TAG,我們經(jīng)常見如下代碼

private static final String TAG = Xxx.class.getSimpleName();

這樣姚糊,常量TAG就被賦值了該類的簡(jiǎn)單名稱贿衍,即該類的類名。描述符是用來描述字段的數(shù)據(jù)類型救恨,在方法中贸辈,描述符用來記錄方法的參數(shù)列表(包括數(shù)量、類型和順序)返回值肠槽。根據(jù)描述符規(guī)則擎淤,基本數(shù)據(jù)類型、Void無返回值類型都要一個(gè)大寫字母表示秸仙,對(duì)象類型則是一個(gè)大寫L接類的全限定名表示嘴拢。如圖,
Figure7 描述符標(biāo)識(shí)字符

數(shù)組類型中每一個(gè)維度用" [ "表示寂纪。方法中描述符席吴,按照先參數(shù)列表,后返回值的順序描述捞蛋。舉例孝冒,

void test(){ ... }     相應(yīng)的描述符為  ()V
int demo(int i, float j, boolean k){ ... }  相應(yīng)的描述符為 (IFZ)I   
String toString(){ ... } 相應(yīng)的描述符為 ()Ljava/lang/String   
void test(String[] args, long args1){ ... } 相應(yīng)的描述符為 ([Ljava/lang/StringJ)V

NOTE: 字段表集合中不會(huì)列出從超類或者付接口中繼承而來的字段,但有可能列出原本java代碼中不存在的字段拟杉。譬如在內(nèi)部類中為了保持對(duì)外部類的訪問性庄涡,會(huì)自動(dòng)添加指向外部類實(shí)例的字段。

  • 方法集合

    同字段表結(jié)構(gòu)類似捣域,方法表的結(jié)構(gòu)包含了access_flags啼染、name_index、descriptor_index焕梅、attributes_count、attributes五項(xiàng)屬性卦洽,相應(yīng)的數(shù)據(jù)類型也相同贞言。
    Figure8 方法表結(jié)構(gòu)
    Figure9 方法訪問標(biāo)記

    這里你可能會(huì)問了,access_flags涉及方法的修飾符阀蒂,name_index涉及了方法名稱该窗,descriptor_index中涉及了方法的參數(shù)、返回類型蚤霞,那方法體哪里去了酗失?方法體代碼經(jīng)過編譯成為字節(jié)碼指令,存放在方法屬性表集合中的一個(gè)名稱為Code的屬性中昧绣,Code屬性會(huì)在后面提到规肴。

  • 屬性表集合

    class文件、字段表、方法表都有屬性表集合(零個(gè)或多個(gè))拖刃,先來看一下標(biāo)準(zhǔn)的屬性表結(jié)構(gòu)Figure10删壮,共同項(xiàng)包括attribute_name_index(不同的屬性表,該值不同)兑牡、attribute_length央碟,最后一項(xiàng)為屬性具體內(nèi)容。
    Figure10 標(biāo)準(zhǔn)屬性表結(jié)構(gòu)
  1. Code屬性表均函。前面提到過亿虽,Java源代碼經(jīng)過編譯器編譯后,字節(jié)碼指令存在Code屬性中苞也。它是class文件中最重要的一個(gè)屬性洛勉。Figure11是Code屬性表的結(jié)構(gòu)。其中墩朦,max_stack表示操作數(shù)棧的最大深度值坯认。在執(zhí)行方法時(shí),操作數(shù)棧都不會(huì)超過這個(gè)深度氓涣。max_locals表示局部變量表所需的存儲(chǔ)空間牛哺。單位為Slot,Slot是虛擬機(jī)為局部變量分配內(nèi)存所使用的最小單位劳吠。對(duì)byte引润、char、short痒玩、int淳附、float、boolean蠢古、returnAddress等長(zhǎng)度不超過32位的數(shù)據(jù)類型奴曙,每個(gè)局部變量占用1個(gè)Slot,而double和long這兩種64位的數(shù)據(jù)類型則需要兩個(gè)Slot來存儲(chǔ)草讶。code_length和code用來存儲(chǔ)Java源程序編譯后生成的字節(jié)碼指令洽糟。
    Figure11 Code屬性表結(jié)構(gòu)
  2. LineNumberTable屬性。LineNumberTable屬性用于描述Java源碼行號(hào)與字節(jié)碼行號(hào)(字節(jié)碼的偏移量)之間的對(duì)應(yīng)關(guān)系堕战。
    Figure12 LineNumberTable屬性表結(jié)構(gòu)

    注意到line_numer_table的類型位line_number_info表坤溃,line_number_info表包括了start_pc和line_number兩個(gè)u2類型的數(shù)據(jù)項(xiàng),前者是字節(jié)碼行號(hào)嘱丢,后者是Java源碼行號(hào)薪介。

  3. SourceFile屬性。SourceFile屬性用于記錄生成這個(gè)class文件的源碼文件名稱
    Figure13 SourceFile屬性表結(jié)構(gòu)
  4. BootstrapMethod屬性越驻。BootstrapMethod屬性與invokedynamic指令有關(guān)汁政,雖然在TestClass源碼中沒有涉及到道偷,但我這里想著記錄一下。這個(gè)屬性用于保存invokedynamic指令引用的引導(dǎo)方法限定符烂完。invokedynamic指令的內(nèi)容有待進(jìn)一步深究试疙,這里就不詳細(xì)說了。
    Figure14 BootstrapMethod屬性表結(jié)構(gòu)

當(dāng)然抠蚣,屬性表中不止這幾種屬性祝旷,還有Exceptions屬性、LocalVariableTable屬性嘶窄、ConstantValue屬性怀跛、InnerClasses屬性等,這些在后面有機(jī)會(huì)碰到再進(jìn)行補(bǔ)充柄冲。

介紹了class文件的組成部分吻谋,下面我們來結(jié)合具體的一段測(cè)試代碼的字節(jié)碼,鞏固一下上面所講到內(nèi)容现横。

/** 測(cè)試代碼選自《深入理解JVM》一書第六章漓拾,因?yàn)樵诜赐谱止?jié)碼過程中預(yù)防出現(xiàn)解
決不了的疑問,所以直接按照書中的測(cè)試代碼進(jìn)行練習(xí)戒祠,這樣如果哪部分字節(jié)碼有疑問骇两,
也能有所參照 */

//TestClass.java
package org.fenixsoft.clazz; 
public class TestClass{ 
    private int m;
    public int inc(){ 
        return m + 1;
    } 
}

編譯得到TestClass.class文件。在分析具體的字節(jié)碼內(nèi)容之前姜盈,先獲取反編譯文件低千。方便在分析字節(jié)碼時(shí)核對(duì)校驗(yàn)。(命令 javap -verbose TestClass馏颂,可以看到示血,輸出包括版本號(hào)、access_flags救拉、常量池难审、方法)


Figure15 反編譯class文件

使用WinHex打開TestClass.class文件,查看字節(jié)碼文件具體內(nèi)容

Figure16 class文件的具體內(nèi)容

為了方便分析亿絮,將16進(jìn)制的數(shù)字按照原來樣式復(fù)制到Excel文件中剔宪,具體分析后的結(jié)果如下,
Figure17 最后的分析結(jié)果

(Excel文件我會(huì)在文末提供云盤下載)
下面對(duì)分析結(jié)果進(jìn)行詳細(xì)講解壹无。

  1. class文件最開頭的是,u4類型的魔數(shù)感帅。<CA FE BA BE>
  2. 接著斗锭,u2類型的次版本號(hào)。<00 00>
  3. 接著失球,u2類型的主版本號(hào)岖是。<00 34>(說明一下帮毁,Java的版本號(hào)是從45開始,之后的每個(gè)JDK大版本發(fā)布豺撑,主版本號(hào)向上加1烈疚。這里我使用的是JDK1.8,十六進(jìn)制的34轉(zhuǎn)為十進(jìn)制就是52聪轿,即對(duì)應(yīng)的JDK1.8版本爷肝。)
  4. 接著,u2類型的constant_pool_count(常量池容量計(jì)數(shù))陆错。<00 13>(十進(jìn)制為19灯抛,即0-18,共19個(gè)音瓷。但是真正的計(jì)數(shù)是從1開始对嚼,也就是說,實(shí)際的常量池?cái)?shù)量是18個(gè)绳慎,這一點(diǎn)可以從反編譯class文件中得到驗(yàn)證纵竖,常量池中確實(shí)有18個(gè)常量。至于第0項(xiàng)常量杏愤,我引用一下《深入理解JVM》書中原話靡砌,書中沒有對(duì)這種特定情況進(jìn)行進(jìn)一步闡述,我這里也存疑)

設(shè)計(jì)者將第0項(xiàng)常量空出來是有特殊考慮的声邦,這樣做的目的在于滿足后面某些指向常量池的索引值的數(shù)據(jù)在特定情況下需要表達(dá)“不引用任何一個(gè)常量池項(xiàng)目” 的含義乏奥,這種情況就可以把索引值置為0來表示。

  1. 接著就是常量池中的具體元素了亥曹。前面提到邓了,常量池中的元素表的一個(gè)共同點(diǎn)就是第一個(gè)字節(jié)存放的是常量類型標(biāo)記tag,tag取值有1媳瞪、3-12骗炉、15、16蛇受、18共14個(gè)句葵。這個(gè)tag就是用來識(shí)別常量池中元素的重要標(biāo)記。tag對(duì)應(yīng)的表需要去Figure 3中查找兢仰。

第1個(gè)常量<0A 00 04 00 0F>乍丈。0A標(biāo)識(shí)這是一個(gè)CONSTANT_Methodref_info常量,查看Figure3中CONSTANT_Methodref_info表結(jié)構(gòu)可知把将,<00 04>是聲明方法的類描述符轻专,<00 0F>是方法的名稱及類型描述符。查看Figure 15可知察蹲,<00 04>表示java/lang/Object请垛,<00 0F>表示"<init>":()V催训。綜合起來看就是java/lang/Object."<init>":()V,與Figure15中常量池第一項(xiàng)正確對(duì)應(yīng)宗收。

第2個(gè)常量<09 00 03 00 10>漫拭。09標(biāo)識(shí)這是一個(gè)CONSTANT_Fieldref_info常量,查看Figure3中CONSTANT_Fieldref_info表結(jié)構(gòu)可知混稽,<00 03>是聲明字段的類描述符采驻,<00 10>是字段描述符。查閱Figure15可知荚坞,<00 03>表示org/fenixsoft/clazz/TestClass挑宠,<00 10>表示 m:I。綜合看颓影,為org/fenixsoft/clazz/TestClass.m:I各淀,同F(xiàn)igure15常量池中第二項(xiàng)對(duì)應(yīng)正確。

第3個(gè)常量<07 00 11>诡挂。07標(biāo)識(shí)這是一個(gè)CONSTANT_Class_info常量碎浇,查看CONSTANT_Class_info表結(jié)構(gòu)及Figure15,可知<00 11>是類的全限定名org/fenixsoft/clazz/TestClass璃俗。

第4個(gè)常量<07 00 12>奴璃。表示類全限定名java/lang/Object。

第5個(gè)常量<01 00 01 6D>城豁。01標(biāo)識(shí)這是一個(gè)CONSTANT_Utf8_info常量苟穆,查看CONSTANT_Utf8_info表結(jié)構(gòu),可知<00 01>表示該UTF-8編碼的字符串占用字節(jié)數(shù)為1唱星。所有雳旅,往后一個(gè)字節(jié)<6D>就是UTF-8編碼的字符串,通過ascii碼表可知间聊,<6D>為m攒盈。

第6個(gè)常量<01 00 01 49>。表示字符1哎榴。從第7個(gè)常量開始到第18個(gè)型豁,使用WinHex幫助查看。
第7個(gè)常量<01 00 06 3C 69 6E 69 74 3E>尚蝌。01標(biāo)識(shí)這是一個(gè)CONSTANT_Utf8_info常量迎变,這個(gè)字符串使用UTF-8縮略編碼。這里直接引用《深入理解JVM》中一段來說UTF-8縮略編碼與普通UTF-8編碼的區(qū)別飘言。

從'\u0001'到'\u007f'之間的字符的縮略編碼使用一個(gè)字節(jié)表示氏豌;從'\u0080'到'\u07ff'之間的所有字符的縮略編碼用兩個(gè)字節(jié)表示;從'\u0800'到'\uffff'之間的所有字符的縮略編碼就按照普通UTF-8編碼規(guī)則使用三個(gè)字節(jié)表示热凹。

所以泵喘,這個(gè)常量再逐個(gè)字節(jié)去分析就比較困難了,我們結(jié)合WinHex查看般妙,結(jié)果一目了然纪铺,這個(gè)字符串為"<init>"
image.png

第8個(gè)常量<01 00 03 28 29 56>。字符串為"()V"
image.png

第9個(gè)常量<01 00 04 43 6F 64 65>碟渺。字符串為"Code"
image.png

第10個(gè)常量<01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65>鲜锚。字符串為"LineNumberTable"
image.png

第11個(gè)常量<01 00 03 69 6E 63>。字符串為"inc"
image.png

第12個(gè)常量<01 00 03 28 29 49>苫拍。字符串為" ()I "芜繁。
image.png

第13個(gè)常量<01 00 0A 53 6F 75 72 63 65 46 69 6C 65>。字符串為"SourceFile"绒极。
image.png

第14個(gè)常量<01 00 0E 54 65 73 74 43 6C 61 73 73 2E 6A 61 76 61>骏令。字符串為"TestClass.class"。
image.png

第15個(gè)常量<0C 00 07 00 08>垄提。tag為0C榔袋,查詢Figure3可知,這是一個(gè)CONSTANT_NameAndType_info常量铡俐。查詢Figure15凰兑,可知<00 07>表示<init>,<00 08>表示()V审丘,所以該常量為 “<init>:()V”

第16個(gè)常量<0C 00 05 00 06>吏够。同上一個(gè)常量是同一個(gè)類型。為“m:I”滩报。

第17個(gè)常量<01 00 1D 6F 72 67 2F 66 65 6E 69 78 73 6F 66 74 2F 63 6C 61 7A 7A 2F 54 65 73 74 43 6C 61 73 73>锅知。字符串為"org/fenixsoft/clazz/TestClass"。
image.png

第18個(gè)常量<01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74>露泊。字符串為"java/lang/Object"喉镰。
image.png
  1. 接著,u2類型的access_flags<00 21>惭笑。TestClass是一個(gè)普通類侣姆,被public修飾,使用JDK1.8編譯器編譯沉噩,所以ACC_PUBLIC捺宗、ACC_SUPER標(biāo)志應(yīng)為真,所以access_flags = 0x0001 | 0x0020 = 0x0021川蒙。

  2. 接著蚜厉,u2類型的類索引、u2類型的父類索引畜眨、u2類型的接口數(shù)量昼牛、u2類型的接口索引术瓮。其中,
    <00 03>為 org/fenixsoft/clazz/TestClass
    <00 04>為 java/lang/Object
    <00 00> 則表示當(dāng)前類實(shí)現(xiàn)的接口數(shù)量為0贰健。接口數(shù)量為0時(shí)胞四,后面的接口索引不再占用任何字節(jié)。

  3. 接著伶椿,u2類型的字段數(shù)量fields_count及fields_count大小的字段索引fields辜伟。
    <00 01>表示當(dāng)前類中有一個(gè)字段。
    <00 02 00 05 00 06 00 00>脊另。查看字段表結(jié)構(gòu)导狡,
    <00 02>表示字段的access_flags被設(shè)置為ACC_PRIVATE;
    <00 05>查詢Figure15,為m
    <00 06>查詢Figure15, 為I
    <00 00>表示attrubutes_count為0偎痛。所以旱捧,后面的attributes也不再占用任何字節(jié)。
    這樣綜合一下看彼,可以推斷為 private int m;

  4. 接著廊佩,u2類型的方法數(shù)量methods_count及methods_count大小的方法集合methods。<00 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 00 0A 00 00 00 06 00 01 00 00 00 03 >靖榕。我們劃分著看标锄,
    <00 02>表示methods_count值為2,即有兩個(gè)方法茁计。接著看具體是哪兩個(gè)方法料皇。
    <00 01 00 07 00 08> methods_count之后就是methods,<00 01>為access_flags星压,查詢Figure 9可知践剂,該方法是public公共方法。<00 07 00 08>則是方法名稱及描述符娜膘,查詢Figure 15可知逊脯,該方法為<init>:()V。即竣贪,默認(rèn)構(gòu)造方法 public void TestClass(){ ... }
    <00 01>描述符后面是占用2個(gè)字節(jié)的attributes_count军洼,即屬性表數(shù)量。這里表示TestClass類默認(rèn)構(gòu)造方法有一個(gè)屬性表演怎。
    <00 09 00 00 00 1D 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00>查看屬性表結(jié)構(gòu)匕争,首先是u2類型的屬性名稱索引attribute_name_index,查閱Figure 15, <00 09>常量為“Code”爷耀,也就是說這一段數(shù)據(jù)是Code屬性表甘桑。查看Code屬性表結(jié)構(gòu),之后4個(gè)字節(jié)的attribute_length為29(<00 00 00 1D>)。也就是后面的29個(gè)字節(jié)都是該屬性的內(nèi)容跑杭。<00 01>表示操作數(shù)棧的最大深度值為1铆帽。<00 01>表示局部變量表的最大容量為1。接下來的code_length和code用來存儲(chǔ)TestClass類編譯后生成的字節(jié)碼指令艘蹋。<00 00 00 05>表示code_length為5锄贼,所有接下的5個(gè)字節(jié)<2A B7 00 01 B1>就是存放的字節(jié)碼指令。每一個(gè)字節(jié)碼指令占用一個(gè)字節(jié)女阀,所以這里有5個(gè)字節(jié)碼指令。2A表示aload_0屑迂,B7表示invokespecial浸策,<00 01>表示invokespecial的參數(shù),查詢Figure15可知惹盼,為Method java/lang/Object."<init>":()V庸汗。B1表示return。接下來的<00 00>是exception_table_length手报,默認(rèn)構(gòu)造方法沒有拋出異常蚯舱,所以后面的exception_table不占用任何字節(jié)。
    <00 01> 表示attrubutes_count掩蛤。(注意枉昏,這是Code屬性表中的一部分)
    <00 0A 00 00 00 06 00 01 00 00 00 03 > 接著看attrubutes(注意,這是Code屬性表中的一部分)揍鸟。<00 0A>表示這是一個(gè)LineNumberTable屬性表兄裂。查看LineNumberTable屬性表結(jié)構(gòu),<00 00 00 06>為attribute_length阳藻,<00 01>為line_number_table_length晰奖,<00 00 00 03>則是line_number_info類型的line_number_table。

以上就是TestClass默認(rèn)構(gòu)造方法的所有字節(jié)碼信息腥泥。再貼上反編譯后的文件內(nèi)容匾南,對(duì)照著看一下該方法都有什么信息。

 public org.fenixsoft.clazz.TestClass();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

接下來是第二個(gè)方法蛔外,就不再繼續(xù)分析蛆楞,直接貼上對(duì)應(yīng)的信息。
<00 01 00 0B 00 0C 00 01 00 09 00 00 00 1F 00 02 00 01 00 00 00 07 2A B4 00 02 04 60 AC 00 00 00 01 00 0A 00 00 00 06 00 01 00 00 00 06>

<00 01 00 0B 00 0C> //access_flags name_index descriptor_inex (public int inc)
<00 01> //attributes_count
<00 09 00 00 00 1F 00 02 00 01 00 00 00 07 2A B4 00 02 04 60 AC 00 00 00 01 00 0A 00 00 00 06 00 01 00 00 00 06>
再細(xì)分<00 09>Code屬性表; <00 00 00 1F>attribute_length; <00 02>max_stack; <00 01>max_locals; <00 00 00 07>code_length; <2A B4 00 02 04 60 AC>code; <00 00>exception_table_length; <00 01>attrubutes_count; <00 0A>LineNumberTable屬性; <00 00 00 06 00 01 00 00 00 06>line_number_table_length及l(fā)ine_number_info

  1. 接著冒萄,屬性表集合臊岸,attributes_count與attributes,這也是class文件中的最后一個(gè)組成部分尊流。<00 01 00 0D 00 00 00 02 00 0E>, 其中帅戒,<00 01>是attributes_count,為1。查閱Figure 15逻住,可知<00 0D>表示這是一個(gè)SourceFile屬性钟哥。查看SourceFile屬性表結(jié)構(gòu)。<00 00 00 02>為attribute_length瞎访,肉眼可見確實(shí)只剩下兩個(gè)字節(jié)的數(shù)據(jù)了腻贰。<00 0E>為sourcefile索引sourcefile_index。查閱Figure 15可知扒秸,為TestClass.class播演。
后記

終于到后記部分了,呼伴奥。再回頭看一下java源碼,

package org.fenixsoft.clazz; 

public class TestClass{ 
    private int m;
    public int inc(){ 
        return m + 1;
    } 
}

你問我什么感覺写烤?EMMM,拾徙,洲炊,,尼啡,暂衡,幸虧沒手賤多寫一個(gè)變量,多寫一個(gè)方法??崖瞭。最后狂巢,解析字節(jié)碼這種事情還是交給虛擬機(jī)做吧。最后奉上excel文件鏈接读恃,不嫌麻煩的小伙伴可以搭配excel文件對(duì)class文件結(jié)構(gòu)學(xué)習(xí)一波吧隧膘。
鏈接:https://pan.baidu.com/s/10JRSAhAXeU17n4f9Wom4wg
提取碼:sg90

參考資料:

  1. 《深入理解Java虛擬機(jī)》
  2. 《Java虛擬機(jī)規(guī)范(JavaSE 7版)》
  3. https://www.cnblogs.com/longjee/p/8675771.html
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市寺惫,隨后出現(xiàn)的幾起案子疹吃,更是在濱河造成了極大的恐慌,老刑警劉巖西雀,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萨驶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡艇肴,警方通過查閱死者的電腦和手機(jī)腔呜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來再悼,“玉大人核畴,你說我怎么就攤上這事〕寰牛” “怎么了谤草?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我丑孩,道長(zhǎng)冀宴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任温学,我火速辦了婚禮略贮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仗岖。我一直安慰自己逃延,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布轧拄。 她就那樣靜靜地躺著真友,像睡著了一般。 火紅的嫁衣襯著肌膚如雪紧帕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天桅打,我揣著相機(jī)與錄音是嗜,去河邊找鬼。 笑死挺尾,一個(gè)胖子當(dāng)著我的面吹牛鹅搪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遭铺,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼丽柿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了魂挂?” 一聲冷哼從身側(cè)響起甫题,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涂召,沒想到半個(gè)月后坠非,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡果正,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年炎码,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秋泳。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡潦闲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迫皱,到底是詐尸還是另有隱情歉闰,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站新娜,受9級(jí)特大地震影響赵辕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜概龄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一还惠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧私杜,春花似錦蚕键、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铝耻,卻和暖如春誊爹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓢捉。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工频丘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泡态。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓搂漠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親某弦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子桐汤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容