前言
[Class文件結(jié)構(gòu)] 1- 概述 文中對(duì)Class文件結(jié)構(gòu)進(jìn)行了基本闡述遭铺,本文繼續(xù)分析常量池中的具體類型丽柿。
CONSTANT_Class_info
表中第一項(xiàng)常量一定是CONSTANT_Class_info類型恢准,它的結(jié)構(gòu)較為簡單。
tag表示具體類型(u1)甫题,對(duì)應(yīng)著前言中的圖馁筐,CONSTANT_Class_info類型應(yīng)該為7,name_index表示索引值(u2)坠非,它指向常量池中一個(gè)CONSTANT_Utf8_info常量類型敏沉。
查看示例Class文件,發(fā)現(xiàn)tag為7炎码,而name_index為2盟迟,表示當(dāng)前常量為CONSTANT_Class_info,它的名稱是索引值為2的CONSTANT_Utf8_info潦闲。
對(duì)應(yīng)javap內(nèi)容查看攒菠,正好一一對(duì)應(yīng)。
CONSTANT_Utf8_info
CONSTANT_Utf8_info型常量結(jié)構(gòu)如下:
tag表示類型(u1)矫钓,length表示字符串的長度(u2)要尔,bytes即是字符串的編碼。因?yàn)閘ength是u2值新娜,即是2個(gè)字節(jié)赵辕,因此字符串的長度最大為65535,如果在代碼中定義超過此長度的變量或方法名概龄,將會(huì)無法編譯还惠。
tag值為1,length為1D私杜,即為29蚕键,后面的29個(gè)u1類型數(shù)據(jù),每一個(gè)都對(duì)應(yīng)著一個(gè)字母衰粹,查看右邊的ANSI ASCII面板锣光,正好可以看到對(duì)應(yīng)的字母,發(fā)現(xiàn)即是Class的全限類名铝耻。與前文提到的CONSTANT_Class_info正好一一對(duì)應(yīng)誊爹。
訪問標(biāo)志
常量池訪問結(jié)束之后,緊接著的2個(gè)字節(jié)代表訪問標(biāo)志(access_flags)瓢捉,這個(gè)標(biāo)志用于識(shí)別一些類或接口層次的訪問信息频丘,包括:這個(gè)Class是類還是接口;是否定義為public類型泡态;是否定義為abstract類型搂漠;如果是類的話,是否被聲明為final等等某弦。具體如下:
如果沒有用到的標(biāo)志則為0桐汤,與用到的標(biāo)志一起作或運(yùn)算而克,當(dāng)前類為public類,所以具體值為 0x0001 | 0x0020 = 0x0021惊科。
類索引拍摇、父類索引與接口索引集合
類繼承哪個(gè)父類,實(shí)現(xiàn)了哪些接口馆截,這些信息在Class文件中由這3項(xiàng)數(shù)據(jù)來準(zhǔn)確描述充活。
類索引(this_class)和父類索引(super_class)都是一個(gè)u2類型的數(shù)據(jù),而接口索引集合是一組u2數(shù)據(jù)的集合蜡娶。類索引用于確定類的全限定名混卵,父類索引用于確定父類的全限定名,接口索引用于確定接口的全限定名窖张。
上述3個(gè)數(shù)據(jù)排列在訪問標(biāo)志之后幕随。類索引和父類索引指向一個(gè)類型為CONSTANT_Class_info的類描述符常量。
示例中沒有實(shí)現(xiàn)接口宿接,它的數(shù)據(jù)如下:
類索引為1赘淮,父類索引為3,接口集合大小為0睦霎,根據(jù)javap內(nèi)容查看梢卸,也是一一對(duì)應(yīng)。
字段表集合
字段表較復(fù)雜副女,用于描述接口或類中聲明的變量蛤高。字段包含了類級(jí)變量(static修飾的類變量)或?qū)嵗?jí)變量,但不包括方法內(nèi)部聲明的變量碑幅。
字段包含的信息有:
- 字段的作用域及其它可能的修飾符(final戴陡,static,volatile之類)
- 字段數(shù)據(jù)類型(基本數(shù)據(jù)類型沟涨、數(shù)組或?qū)ο螅?/li>
- 字段名稱
字段表的結(jié)構(gòu)如下:
access_flags(字段的作用域及其它修飾符)同 訪問標(biāo)志 一節(jié)中類似恤批,也是通過或運(yùn)算確定。
示例Class中內(nèi)容如下:
access_flags為2裹赴,對(duì)照字段訪問標(biāo)志可知喜庞,access修飾符為private,和代碼正好對(duì)應(yīng)篮昧。
跟隨access_flags標(biāo)志的是兩項(xiàng)索引值,name_index和descriptor_index笋妥。它們都分別是對(duì)常量池的引用懊昨,分別代表著字段的簡單名稱及字段或方法的描述符。
接下來解釋一下春宣,全限定名酵颁、簡單名稱嫉你、描述符這三個(gè)概念。
全限定名躏惋,以類名為示例幽污,就是全包名+類名。簡單名稱就是指沒有參數(shù)修飾的字段或方法名稱簿姨,比如示例代碼中m和方法inc即是簡單名稱距误。描述符的作用是用來描述字段的數(shù)據(jù)類型、方法的參數(shù)列表和返回值扁位。示例代碼中m的描述符為 I准潭,I表示int型。
基本數(shù)據(jù)類型(byte,char,double,float,int,long,short,boolean)及代表無返回值的void類型都用一個(gè)大寫字符來表示域仇,而對(duì)象類型則用字符L加對(duì)象的全限定名來表示刑然。數(shù)組類型,每一個(gè)維度將使用一個(gè)前置的“[”字符來描述暇务,如定義 String[][] 類型的二維數(shù)組泼掠,將被記錄為 [[Ljava/lang/String; ,一個(gè)整形數(shù)組 int[] 將被記錄為 [I 垦细。
用描述符來描述方法的時(shí)候择镇,按照先參數(shù)列表后返回值的順序描述,參數(shù)列表按照參數(shù)順序放在一組小括號(hào)()內(nèi)蝠检。如方法 void inc() 的描述符為 ()V 沐鼠。
回看示例Class文件數(shù)據(jù), 0001表示字段個(gè)數(shù)叹谁,只有1個(gè)饲梭。access_flags值為2,對(duì)照表格可知是private焰檩,name_index值為5憔涉,查看常量池中索引為5的值,為m析苫,而描述符值為6兜叨,查看常量池中索引為6的值,為I衩侥。
在示例Class文件中国旷,字段表結(jié)構(gòu)中的attributes_count和attributes沒有,這兩個(gè)因素留待方法表中分析茫死。