從上一篇博客(Java Class文件解析)的分析可以看出,Class文件中的各項(xiàng)是按照一定的包含關(guān)系和次序關(guān)系存儲(chǔ)的,因此Class文件可以從頭到尾地被解析為各個(gè)項(xiàng)。下面請(qǐng)看一個(gè)解析實(shí)例:
這里我們以非常著名的HelloWorld為實(shí)例來(lái)分析Java Class文件。HelloWorld的源代碼如下:
package bytecodeResearch;


public class HelloWorld
{

//定義兩個(gè)靜態(tài)變量
private static String str_1 = "Hello";
private static String str_2 = "World";

/** *//**
* 靜態(tài)方法
* @param str
*/
private static void Hello(String str)

{
System.out.println(str);
}

/** *//**
* 靜態(tài)方法
* @param str
*/
private static void World(String str)

{
System.out.println(str);
}

/** *//**
* 程序入口方法
* @param args
*/
public static void main(String[] args)

{
Hello(str_1);
World(str_2);
}
}

編譯單元HelloWorld.java文件經(jīng)過編譯器編譯之后,將得到一個(gè)HelloWorld.class文件。需要說(shuō)明的是,經(jīng)過不同的編譯器編譯之后得到的HelloWorld.class文件可能不一樣,本人選用的開發(fā)工具是Eclipse3.3-europa版本,Eclipse SDK自帶的JDT工具內(nèi)置了增量式Java編譯器,這個(gè)編譯器與javac完全兼容。本人以下的分析都是基于Eclipse自帶的編譯器編譯得到的Class文件,如果有人用了Jikes編譯器、GNU的編譯器或者其它版本的javac編譯器的話,得到的Class文件跟我的可能不完全一樣的話,但是Class文件的格式肯定是一樣的,因此分析的原理也都是一樣的,即都是基于上一篇博客(Java Class文件解析)給出的ClassFile結(jié)構(gòu)圖示。
經(jīng)過Eclipse3.3編譯得到的Class文件內(nèi)容如下:
注:該Class的內(nèi)容是經(jīng)過解析的,即將.class文件的二進(jìn)制字節(jié)流轉(zhuǎn)換為16進(jìn)制的數(shù)字字符流形式。由于UE查看Class文件時(shí),用一個(gè)8位的16進(jìn)制數(shù)來(lái)表示每一行起始字節(jié)對(duì)應(yīng)于Class文件中的字節(jié)號(hào),為了不造成視覺差異,本人寫了一段程序來(lái)讀寫Class文件內(nèi)容,其輸出結(jié)果就是上面這段內(nèi)容,每16個(gè)字節(jié)占一行,每個(gè)字節(jié)均拆解成2位16進(jìn)制整數(shù)字符,每一行左端的8位的16進(jìn)制整數(shù)就表示該行的起始字節(jié)對(duì)應(yīng)于原Class文件中的字節(jié)號(hào)。這個(gè)程序貼在了我第一篇blog里--一個(gè)讀取Class文件的示例程序了。
好了,閑言少敘!下面開始正式解析這個(gè)Class文件。
按照上一篇博客(Java Class文件解析)介紹的ClassFile結(jié)構(gòu)圖示以及對(duì)ClassFile結(jié)構(gòu)的詳細(xì)分析,可以將HelloWorld.class文件的各個(gè)項(xiàng)順序地解析如下:
(1) 前4個(gè)字節(jié)0xCAFEBABE是magic項(xiàng)的內(nèi)容。
(2) 接下來(lái)的2個(gè)字節(jié)0x0000是minor_version項(xiàng)的內(nèi)容,即該Class文件的次版本號(hào)0。
(3) 接下來(lái)的2個(gè)字節(jié)0x0031是major_version項(xiàng)的內(nèi)容,即該Class文件的主版本號(hào)為49。這個(gè)主版本號(hào)對(duì)應(yīng)于J2SE5.0的編譯器的編譯結(jié)果。如果你用J2SE6.0的編譯器來(lái)編譯此HelloWorld.java程序的話,得到的主版本號(hào)應(yīng)該是0x0032,即50。
(4) 接下來(lái)的2個(gè)字節(jié)0x0031是constant_pool_count項(xiàng)的內(nèi)容,它表示接下來(lái)共有連續(xù)的49-1=48個(gè)constant_pool表項(xiàng)。
(5) 緊接著constant_pool_count項(xiàng)后面的是常量池列表項(xiàng)。常量池列表項(xiàng)的長(zhǎng)度是可變的,這是因?yàn)椴煌某A砍乇眄?xiàng)的格式是不一樣的。
5.1)先來(lái)分析第一個(gè)常量池表項(xiàng)。上一篇博客(Java Class文件解析)中提到,每個(gè)常量池表項(xiàng)的具體格式是要根據(jù)其tag項(xiàng)(即該常量池表項(xiàng)的第一個(gè)字節(jié))來(lái)決定。因此,constant_pool_count項(xiàng)后面的第一字節(jié)就是第一個(gè)常量池表項(xiàng)的tag項(xiàng)的內(nèi)容,在這里為0x07,cp_type表可知,tag值為0x07的對(duì)應(yīng)CONSTANT_Class結(jié)構(gòu)的常量池表項(xiàng)。再查閱CONSTANT_Class_info表,該表結(jié)構(gòu)如下:
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
根據(jù)《JVM Spec》(2nded)中對(duì)此表的說(shuō)明可知,1個(gè)字節(jié)的tag項(xiàng)就是剛才讀取的值0x07,而后的2個(gè)字節(jié)的name_index項(xiàng)表示對(duì)一個(gè)CONSTANT_Utf8_info表的索引,該索引項(xiàng)包含了類或者接口的完全限定名稱。對(duì)于HelloWorld.class這個(gè)類來(lái)說(shuō),第一個(gè)常量池表項(xiàng)就是一個(gè)CONSTANT_Class_info表的結(jié)構(gòu),其tag項(xiàng)的值是0x07,其name_index項(xiàng)的值是0x0002,即該常量池表項(xiàng)指向索引為0x0002的常量池表項(xiàng)。
5.2)再來(lái)分析第二個(gè)常量池表項(xiàng)。其tag項(xiàng)值為0x01,查閱cp_type表可知,該常量池表項(xiàng)是一個(gè)CONSTANT_ Utf8_info表的結(jié)構(gòu),然后我們查閱CONSTANT_ Utf8_info表,該表結(jié)構(gòu)如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
根據(jù)《JVM Spec》(2nded)中對(duì)此表的說(shuō)明可知,1個(gè)字節(jié)的tag項(xiàng)的值就是0x01,2個(gè)字節(jié)的length項(xiàng)給出了后續(xù)的bytes數(shù)組的長(zhǎng)度(字節(jié)數(shù)),在這里為0x001B,即其后續(xù)的27個(gè)字節(jié)均是該bytes數(shù)組的內(nèi)容,它包含了按照變體UTF-8格式存儲(chǔ)(不是標(biāo)準(zhǔn)的UTF-8格式啊,具體的差別請(qǐng)查閱那兩個(gè)參考資料,都有說(shuō)明)的字符串中的字符。按照此變體格式可以將這27個(gè)字節(jié)解析為“bytecodeResearch/HelloWorld”,這27個(gè)字符實(shí)際上就是該ClassFile的完全限定名稱,這是為什么呢?因?yàn)榈谝粋€(gè)常量池表項(xiàng)是CONSTANT_Class_info結(jié)構(gòu)的,其name_index項(xiàng)指向的常量池表項(xiàng)包含了類或者接口的完全限定名稱,第二個(gè)常量池表項(xiàng)正是第一個(gè)常量池表項(xiàng)中name_index項(xiàng)所指向的常量池表項(xiàng),因此“bytecodeResearch/HelloWorld”這27個(gè)字符就是該ClassFile的完全限定名稱(注:是完全限定名稱的內(nèi)部形式,下同)。
5.3)再來(lái)分析第三個(gè)常量池表項(xiàng)。第二個(gè)常量池表項(xiàng)后的第一個(gè)字節(jié)為0x07,由cp_type表可知,tag值為0x07的對(duì)應(yīng)CONSTANT_Class結(jié)構(gòu)的常量池表項(xiàng)。類似于對(duì)第一個(gè)常量池表項(xiàng)的分析,0x07后面的兩個(gè)字節(jié)為name_index項(xiàng),其值為0x0004,即該常量池表項(xiàng)指向索引為0x0004的常量池表項(xiàng),且該常量池是CONSTANT_Utf8_info表的結(jié)構(gòu)
5.4)下面來(lái)分析第四個(gè)常量池表項(xiàng)。該常量池表項(xiàng)的tag項(xiàng)值又是0x01,類似地,同第二個(gè)常量池表項(xiàng)的分析,該常量池表項(xiàng)也是一個(gè)CONSTANT_ Utf8_info表的結(jié)構(gòu),其length項(xiàng)值為0x0010,即其后續(xù)的bytes數(shù)組的長(zhǎng)度為0x0010個(gè)字節(jié)。按照《JVM Spec》(2nded)中關(guān)于變體UTF-8格式的定義,可以將這16個(gè)字節(jié)解析為“java/lang/Object”,這是Java類層次結(jié)構(gòu)的根類Object類的完全限定名稱。
類似地,可以分析第5,6,7,8,9,10都是一個(gè)CONSTANT_ Utf8_info結(jié)構(gòu),分別表示“str_1”,“Ljava/lang/String”,“str_2”,“<clinit>”,“()V”,“Code”
5.5)…….其他常量池表項(xiàng)的分析原理是類似的,這里就不贅述了。
5.6)第四十八個(gè)常量池表項(xiàng)的解析。經(jīng)過分析,第48個(gè)常量池起始于第000001f0h字節(jié),終止于第00000202h字節(jié)。該常量池表項(xiàng)又是一個(gè)CONSTANT_Utf8_info表的結(jié)構(gòu),其15字節(jié)的bytes數(shù)組項(xiàng)的值可解析為“HelloWorld.java”。由后面的分析說(shuō)明該常量池表項(xiàng)存儲(chǔ)的是該類文件的SourceFile屬性的信息。
好了,該Class文件的常量池部分已經(jīng)解析結(jié)束了!下面開始其它部分的解析:
(6) 在常量池列表項(xiàng)后面的兩個(gè)字節(jié)是該Java類型的access_flags項(xiàng),這里為0x0021。根據(jù)access_flags表可以查到,該值是0x0020和0x0001兩者的和,即該類的修飾符為ACC_PUBLIC+ACC_SUPER,前者表示該類是public類型,后者表示采用invokespecial指令特殊處理對(duì)超類的調(diào)用。具體可以查閱兩本參考資料中關(guān)于JVM指令集的描述J
(7)接下來(lái)的兩個(gè)字節(jié)是this_class項(xiàng),它是一個(gè)對(duì)常量池表項(xiàng)的索引,在這里值為0x0001,即它指向1號(hào)常量池表項(xiàng),而1號(hào)常量池表項(xiàng)是一個(gè)CONSTANT_Class_info結(jié)構(gòu),它指向2號(hào)常量池表項(xiàng),2號(hào)常量池表項(xiàng)的值為bytecodeResearch/HelloWorld,前面提到這是該Class文件的完全路徑名稱的內(nèi)部形式,因此this_class即指bytecodeResearch/HelloWorld。
(8) 接下來(lái)的兩個(gè)字節(jié)是super_class項(xiàng),它是一個(gè)對(duì)常量池表項(xiàng)的索引,在這里值為0x0003, 即它指向3號(hào)常量池表項(xiàng),查一下上面對(duì)3號(hào)常量池表項(xiàng)的分析,它指向4號(hào)常量池表項(xiàng),而4號(hào)常量池表項(xiàng)包含的值為“java/lang/Object”,即super_class的實(shí)際值為“java/lang/Object”。說(shuō)明我們分析的這個(gè)Class文件的超類是java.lang.Object。
(9) 下面的兩個(gè)字節(jié)是interfaces_count項(xiàng),在這里的值為0x0000,這表示由該類直接實(shí)現(xiàn)或者由該接口所擴(kuò)展的超接口的數(shù)量為0,因此該Class文件中的interfaces列表項(xiàng)也就不存在了。
(10)接下來(lái)的字節(jié)應(yīng)該是field項(xiàng)的內(nèi)容了。首先的兩個(gè)字節(jié)是fields_count項(xiàng),這里的值為0x0002,即該類聲明了兩個(gè)字段(變量),亦即該項(xiàng)之后的fields列表項(xiàng)的元素個(gè)數(shù)為2。由于fields列表項(xiàng)的類型為field_info,所以在fields_count項(xiàng)下面的字節(jié)是兩個(gè)連續(xù)的field_info結(jié)構(gòu),下面來(lái)詳細(xì)分析這兩個(gè)具體的field_info結(jié)構(gòu);
10.1)第一個(gè)field_info,即第一個(gè)字段的相關(guān)信息。
10.1.1)首先的兩個(gè)字節(jié)是第一個(gè)field的access_flags項(xiàng),在這里的值為0x000A,查閱field_access_flags表可知該access_flags項(xiàng)表示的是ACC_PRIVATE+ACC_STATIC,即該字段是由private和static修飾的。
10.1.2)接下來(lái)的兩個(gè)字節(jié)是name_index項(xiàng),在這里的值為0x0005,即該字段的簡(jiǎn)單名稱由第5個(gè)常量池表項(xiàng)描述的,根據(jù)上一篇博客(Java Class文件解析)的分析可知,該常量池包含的信息為str_1,即該字段的名稱為str_1。
10.1.3)接下來(lái)的兩個(gè)字節(jié)是descriptor_index
項(xiàng),
在這里的值為0x0006,即該字段的描述符存儲(chǔ)在
第6個(gè)常量池表項(xiàng),根據(jù)上一篇博客(Java Class文件解析)的分析可知,這個(gè)字段的類型為“Ljava/lang/String”。在Class文件中,“L<classname>”表示一個(gè)類的實(shí)例,其中<classname>是這個(gè)內(nèi)部形式的完全限定類名。
10.1.4)接下來(lái)的兩個(gè)字節(jié)是attributes_count
項(xiàng),
在這里的值為0x0000,即該字段沒有附加的屬性列表。因而也就不用討論attributes[]
項(xiàng)了。
10.2)第二個(gè)field_info,即第二個(gè)字段的相關(guān)信息。類似地,參照第一個(gè)字段信息的分析,我們很快就可以知道該字段的access_flags項(xiàng)為ACC_PRIVATE+ACC_STATIC,名字為str_2,類型描述符為“Ljava/lang/String”,attributes_count
項(xiàng)
的值為0x0000。
(11)接下來(lái)的字節(jié)應(yīng)該是method項(xiàng)的內(nèi)容了。首先的兩個(gè)字節(jié)是methods_count項(xiàng),這里的值為0x0005,即該類聲明了5個(gè)方法,亦即該項(xiàng)之后的methods列表項(xiàng)的元素個(gè)數(shù)為5。由于methods列表項(xiàng)的類型為method_info,所以在methods_count項(xiàng)下面的字節(jié)是5個(gè)連續(xù)的method_info結(jié)構(gòu),下面來(lái)詳細(xì)分析這5個(gè)具體的method_info結(jié)構(gòu):
11.1)第1個(gè)method_info結(jié)構(gòu),即第一個(gè)方法的相關(guān)信息,如方法名、描述符(即方法的返回值及參數(shù)類型)以及一些其它信息。根據(jù)method_info表分析接下來(lái)的字節(jié)碼可以得到:
11.1.1)access_flags項(xiàng),值為0x0008,即給方法的訪問修飾符為ACC_STATIC,它表示這是一個(gè)static方法。
11.1.2)name_index項(xiàng),值為0x0008,第8號(hào)常量池表項(xiàng)存儲(chǔ)的信息為<clinit>即該方法的名稱為<clinit>。這是一個(gè)類與接口初始化方法,這個(gè)方法是由Java編譯器編譯源代碼的時(shí)候產(chǎn)生的,Java編譯器將該類的所有類變量初始化語(yǔ)句和所有類型的靜態(tài)初始化器收集到一起,放到<clinit>方法中,該方法只能被JVM隱式地調(diào)用,專門用于把類型的靜態(tài)變量設(shè)置為它們正確的初始值。
11.1.3)descriptor_index項(xiàng),值為0x0009,第9號(hào)常量池表項(xiàng)存儲(chǔ)的信息為()V,這表示該方法的沒有參數(shù),返回值為void。
11.1.4)attributes_count項(xiàng),值為0x0001,即該方法有一個(gè)屬性。查閱屬性信息表的結(jié)構(gòu),如下所示:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
由這個(gè)表,我們可以知道attributes_count項(xiàng)后面的是這個(gè)屬性的attribute_name_index
項(xiàng),該項(xiàng)的值為0x000A,該屬性的名字信息存儲(chǔ)在第10號(hào)常量池表項(xiàng)里。查閱第10號(hào)常量池表項(xiàng)可知,該屬性的名字為“Code”,然后我們查閱Code_attribute表,結(jié)構(gòu)如下:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
11.1.5)Code_attribute
項(xiàng),該項(xiàng)包含了一個(gè)Java方法,或者實(shí)例初始化方法,或者類或接口初始化方法的JVM指令和輔助信息。每個(gè)JVM的實(shí)現(xiàn)都必須要識(shí)別Code屬性,在每個(gè)method_info結(jié)構(gòu)也必須確切地有一個(gè)Code屬性。下面來(lái)具體分析這個(gè)屬性;
11.1.5.1) attribute_name_index項(xiàng),2個(gè)字節(jié),該項(xiàng)的值為0x000A,查閱第10號(hào)常量池表型包含的信息后知該屬性的名字為“Code”。
11.1.5.2)attribute_length項(xiàng),4個(gè)字節(jié),值為0x00000033,這說(shuō)明該屬性的長(zhǎng)度,出去初始的6個(gè)字節(jié),還有0x33=51個(gè)字節(jié)。如果不愿意討論接下去的51字節(jié)的話,可以直接跳過這51字節(jié)(00000226h-0000025eh字節(jié)),討論下一個(gè)方法。
11.1.5.3)max_stack項(xiàng),2個(gè)字節(jié),值為0x0001,這表示該方法執(zhí)行中任何點(diǎn)操作數(shù)棧上字的最大個(gè)數(shù)為1。
11.1.5.4)max_locals項(xiàng),2個(gè)字節(jié),值為0x0000,這表示該方法使用的局部變量個(gè)數(shù)為0。
11.1.5.5)code_length項(xiàng),4個(gè)字節(jié),值為0x0000000B,這表示該方法的code數(shù)組中字節(jié)的總個(gè)數(shù)為11。
11.1.5.6)code[]項(xiàng),由11.1.5.5)知,該方法的code數(shù)組共占11個(gè)字節(jié)。該code[]項(xiàng)給出了實(shí)現(xiàn)該方法的JVM代碼的實(shí)際字節(jié)。例如第一個(gè)指令是0x12,這是ldc指令,這個(gè)指令表示將一個(gè)常量池表項(xiàng)壓入棧,它需要一個(gè)操作數(shù),而它后面的一個(gè)字節(jié)是0x0B,因此這條指令加上其操作數(shù)就表示將常量池中的第0x0B號(hào)表項(xiàng)壓入棧。接下來(lái)的一個(gè)指令是0xB3,這是putstatic指令,這條指令表示設(shè)置類中靜態(tài)變量的值。它需要兩個(gè)操作數(shù)indexbyte1和indexbyte2,這兩個(gè)操作數(shù)均占一個(gè)字節(jié),JVM執(zhí)行putstatic執(zhí)行時(shí),會(huì)通過計(jì)算(indexbyte1<<8)|indexbyte2生成一個(gè)對(duì)常量池表項(xiàng)的索引,這里的參數(shù)為0x00和0x0D,運(yùn)算結(jié)果是0x0D,因此這條指令的意思就是將操作數(shù)棧的當(dāng)前棧頂元素賦值給0x0D號(hào)常量池表項(xiàng)所存儲(chǔ)的字段(str_1),即完成對(duì)字段str_1的賦值。。同樣,下面的五個(gè)字節(jié)的意思,就是將索引為0x0F的常量池表項(xiàng)壓入操作數(shù)棧,并賦值給(0x00<<)|0x11=0x11號(hào)常量池表項(xiàng)中所存儲(chǔ)的字段(str_2),即完成對(duì)字段str_2的賦值。該Code數(shù)組的最后一個(gè)字節(jié)是0xB1,這是一條不帶操作數(shù)的指令return,它表示從方法中返回,返回值為void。
11.1.5.7)exception_table_length項(xiàng),2個(gè)字節(jié),值為0x0000,這表示該方法的異常處理器的個(gè)數(shù)為0。因此exception_table[ ]就沒有必要討論了。
11.1.5.8)attributes_count項(xiàng),2個(gè)字節(jié),值為0x0002,這表示該方法Code屬性具有兩個(gè)屬性。當(dāng)前由Code屬性定義和使用的兩個(gè)屬性是LineNumberTale和LocalVariableTable屬性。
11.1.5.9)attributes[ ]項(xiàng),由于LineNumberTale和LocalVariableTable兩個(gè)屬性都包含了一些調(diào)試信息,但是兩者都是可選屬性,因此這里就不多討論了。
11.2)第2個(gè)method_info結(jié)構(gòu),即第2個(gè)方法的相關(guān)信息。第2個(gè)方法是實(shí)例初始化方法<init>,這段方法在Class文件中的字節(jié)編號(hào)為:0000025fh-0000029bh字節(jié),感興趣的朋友請(qǐng)繼續(xù)分析下去,原理和第一個(gè)方法的分析是一樣的。
11.3)第3個(gè)method_info結(jié)構(gòu),即第3個(gè)方法的相關(guān)信息。第3個(gè)方法是該類的靜態(tài)方法Hello,這段方法在Class文件中的字節(jié)編號(hào)為:0000029ch-000002dfh字節(jié),感興趣的朋友請(qǐng)繼續(xù)分析下去,原理和第一個(gè)方法的分析是一樣的。
11.4)第4個(gè)method_info結(jié)構(gòu),即第4個(gè)方法的相關(guān)信息。第4個(gè)方法是該類的靜態(tài)方法World,這段方法在Class文件中的字節(jié)編號(hào)為:000002e0h-00000323h字節(jié),感興趣的朋友請(qǐng)繼續(xù)分析下去,原理和第一個(gè)方法的分析是一樣的。
11.5)第5個(gè)method_info結(jié)構(gòu),即第5個(gè)方法的相關(guān)信息。第5個(gè)方法是該類文件的入口main方法,這段方法在Class文件中的字節(jié)編號(hào)為:00000324h-00000370h字節(jié),感興趣的朋友請(qǐng)繼續(xù)分析下去,原理和第一個(gè)方法的分析是一樣的。
(12) attributes_count項(xiàng),2個(gè)字節(jié),該ClassFile的屬性計(jì)數(shù)項(xiàng),它的值為0x0001,表示在后續(xù)的attributes列表中的attributes_info表的總個(gè)數(shù)為1。
(13) 和attributes[ ]項(xiàng),該ClassFile的屬性列表項(xiàng),這是Class文件的最后一項(xiàng)了!由(12)知,該列表項(xiàng)只有一個(gè)表項(xiàng)。由attribute_info表結(jié)構(gòu)
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
可知,attributes_count項(xiàng)后面的兩個(gè)字節(jié)是attribute_name_index項(xiàng),它的值為0x002F,它表示對(duì)常量池編號(hào)為0x002F的表項(xiàng)的一個(gè)索引。這個(gè)索引表項(xiàng)存儲(chǔ)的信息為”SourceFile”,即該ClassFile屬性的名稱為SourceFile,該屬性是一個(gè)可選的定長(zhǎng)屬性,對(duì)于給定的ClassFile結(jié)構(gòu)的attributes列表中不能有多于一個(gè)的SourceFile屬性;查閱SourceFile_attribute表可知,下面的4個(gè)字節(jié)為attribute_length項(xiàng),其值為0x00000002,它表示在該項(xiàng)后面還有2個(gè)字節(jié)的信息。根據(jù)SourceFile_attribute表,最后的這兩個(gè)字節(jié)是sourcefile_index項(xiàng),該項(xiàng)的值是一個(gè)對(duì)CONSTANT_Utf8_info結(jié)構(gòu)的常量池表項(xiàng)的索引,其信息表示的是該Class文件的源文件名稱。在這里值為0x0030,根據(jù)上一篇博客(Java Class文件解析)的分析,第48號(hào)常量池表項(xiàng)存儲(chǔ)的信息可解析為“HelloWorld.java”,這是該Class文件的源文件名稱(不包括路徑)。
好了,到此為止,該Class文件的實(shí)例已經(jīng)全部解析完畢,大功告成:)
posted on 2008-02-03 13:03
獨(dú)孤求敗 閱讀(4863)
評(píng)論(33) 編輯 收藏 所屬分類:
Java ByteCode