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文件組成
- 魔數(shù)
- 次版本號(hào)
- 主版本號(hào)
- 常量池
常量池中存放的內(nèi)容主要包括兩種類型胸蛛,字面量和符號(hào)引用。
其中字面量包括字符串樱报、final常量等葬项;符號(hào)引用包括類和接口的全限定名、字段名稱和描述符迹蛤、方法名和描述符民珍。
常量池中的每一項(xiàng)常量都是一個(gè)表。共有14種類型的表盗飒。
可以看到常量池中涉及的項(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ū)分這些常量類型摊唇。-
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接類的全限定名表示嘴拢。如圖,數(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)
-
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)
-
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)薪介。
-
SourceFile屬性。SourceFile屬性用于記錄生成這個(gè)class文件的源碼文件名稱Figure13 SourceFile屬性表結(jié)構(gòu)
-
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救拉、常量池难审、方法)
使用WinHex打開TestClass.class文件,查看字節(jié)碼文件具體內(nèi)容
為了方便分析亿絮,將16進(jìn)制的數(shù)字按照原來樣式復(fù)制到Excel文件中剔宪,具體分析后的結(jié)果如下,
(Excel文件我會(huì)在文末提供云盤下載)
下面對(duì)分析結(jié)果進(jìn)行詳細(xì)講解壹无。
- class文件最開頭的是,u4類型的魔數(shù)感帅。<CA FE BA BE>
- 接著斗锭,u2類型的次版本號(hào)。<00 00>
- 接著失球,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版本爷肝。)
- 接著,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來表示。
- 接著就是常量池中的具體元素了亥曹。前面提到邓了,常量池中的元素表的一個(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ū)別飘言。
所以泵喘,這個(gè)常量再逐個(gè)字節(jié)去分析就比較困難了,我們結(jié)合WinHex查看般妙,結(jié)果一目了然纪铺,這個(gè)字符串為"<init>"從'\u0001'到'\u007f'之間的字符的縮略編碼使用一個(gè)字節(jié)表示氏豌;從'\u0080'到'\u07ff'之間的所有字符的縮略編碼用兩個(gè)字節(jié)表示;從'\u0800'到'\uffff'之間的所有字符的縮略編碼就按照普通UTF-8編碼規(guī)則使用三個(gè)字節(jié)表示热凹。
第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"。接著,u2類型的access_flags<00 21>惭笑。TestClass是一個(gè)普通類侣姆,被public修飾,使用JDK1.8編譯器編譯沉噩,所以ACC_PUBLIC捺宗、ACC_SUPER標(biāo)志應(yīng)為真,所以access_flags = 0x0001 | 0x0020 = 0x0021川蒙。
接著蚜厉,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é)。接著伶椿,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;接著廊佩,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
- 接著冒萄,屬性表集合臊岸,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
參考資料:
- 《深入理解Java虛擬機(jī)》
- 《Java虛擬機(jī)規(guī)范(JavaSE 7版)》
- https://www.cnblogs.com/longjee/p/8675771.html