- Java虛擬機(jī)字節(jié)碼:從入門到實(shí)戰(zhàn)
- 吳就業(yè)
- 992字
- 2021-01-08 19:08:28
解析方法表
方法表存放一個類或者接口的所有方法。與字段結(jié)構(gòu)一樣,方法結(jié)構(gòu)也有屬性表,方法編譯后的字節(jié)碼指令是存放在方法結(jié)構(gòu)的屬性表中的,對應(yīng)Code屬性。但不是所有方法都會有Code屬性,如接口中的方法不一定會有Code屬性,如抽象方法一定沒有Code屬性。方法包括靜態(tài)方法、以及類的初始化方法<clinit>和類的實(shí)例初始化方法<init>。參照《Java虛擬機(jī)規(guī)范》,方法結(jié)構(gòu)如表2-49所示。
表2-49 方法結(jié)構(gòu)

其中方法名稱索引、方法描述符索引與字段結(jié)構(gòu)中的字段名索引和字段類型描述符索引,都是指向常量池中某個CONSTABT_Utf8_info結(jié)構(gòu)的常量,屬性總數(shù)與屬性表也與字段結(jié)構(gòu)中的一樣,但不同的是,屬性的結(jié)構(gòu)不同,如方法有Code屬性而字段沒有。訪問標(biāo)志也與字段的訪問標(biāo)志有些區(qū)別,如字段有ACC_VOLATILE標(biāo)志而方法沒有。關(guān)于方法的訪問權(quán)限及屬性標(biāo)志如表2-50所示。
表2-50 方法訪問權(quán)限及屬性標(biāo)志映射表


根據(jù)表2-49方法結(jié)構(gòu)創(chuàng)建對應(yīng)的Java類MethodInfo,如代碼清單2-51所示。
代碼清單2-51 MethodInfo類
public class MethodInfo { private U2 access_flags; private U2 name_index; private U2 descriptor_index; private U2 attributes_count; private AttributeInfo[] attributes; }
與字段表的解析流程一樣,我們暫時不關(guān)心屬性表的具體屬性的解析,屬性表的解析只使用通用屬性結(jié)構(gòu)解析。方法表解析器的實(shí)現(xiàn)如代碼清單2-52所示。
代碼清單2-52 方法表解析器
public class MethodHandler implements BaseByteCodeHandler { @Override public int order() { // 排在字段解析器的后面 return 7; } @Override public void read(ByteBuffer codeBuf, ClassFile classFile) throws Exception { classFile.setMethods_count(new U2(codeBuf.get(), codeBuf.get())); // 獲取方法總數(shù) int len = classFile.getMethods_count().toInt(); if (len == 0) { return; } // 創(chuàng)建方法表 MethodInfo[] methodInfos = new MethodInfo[len]; classFile.setMethods(methodInfos); for (int i = 0; i < methodInfos.length; i++) { // 解析方法 methodInfos[i] = new MethodInfo(); methodInfos[i].setAccess_flags(new U2(codeBuf.get(),codeBuf.get())); methodInfos[i].setName_index(new U2(codeBuf.get(), codeBuf.get())); methodInfos[i].setDescriptor_index(new U2(codeBuf.get(), codeBuf.get())); methodInfos[i].setAttributes_count(new U2(codeBuf.get(), codeBuf.get())); // 獲取方法的屬性總數(shù) int attr_len = methodInfos[i].getAttributes_count().toInt(); if (attr_len == 0) { continue; } // 創(chuàng)建方法的屬性表 methodInfos[i].setAttributes(new AttributeInfo[attr_len]); for (int j = 0; j < attr_len; j++) { methodInfos[i].getAttributes()[j] = new AttributeInfo(); // 解析方法的屬性 methodInfos[i].getAttributes()[j] .setAttribute_name_index(new U2(codeBuf.get(), codeBuf.get())); // 獲取屬性info的長度 U4 attr_info_len = new U4(codeBuf.get(), codeBuf.get(), codeBuf.get(), codeBuf.get()); methodInfos[i].getAttributes()[j] .setAttribute_length(attr_info_len); if (attr_info_len.toInt() == 0) { continue; } // 解析info byte[] info = new byte[attr_info_len.toInt()]; codeBuf.get(info, 0, attr_info_len.toInt()); methodInfos[i].getAttributes()[j].setInfo(info); } } } }
將方法表解析器注冊到ClassFileAnalysiser后,我們來編寫單元測試。方法表解析器的單元測試與字段表解析器的單元測試邏輯差不多,如代碼清單2-53所示。
代碼清單2-53 方法表解析器單元測試
public class MethodHandlerTest { private static String getName(U2 name_index, ClassFile classFile) { CONSTANT_Utf8_info name_info = (CONSTANT_Utf8_info) classFile.getConstant_pool()[name_index.toInt() - 1]; return name_info.toString(); } @Test public void testMethodHandlerHandler() throws Exception { ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("Builder.class"); ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf); System.out.println("方法總數(shù):" + classFile.getMethods_count().toInt()); System.out.println(); MethodInfo[] methodInfos = classFile.getMethods(); // 遍歷方法表 for (MethodInfo methodInfo : methodInfos) { System.out.println("訪問標(biāo)志和屬性:" + FieldAccessFlagUtils .toFieldAccessFlagsString(methodInfo.getAccess_flags())); System.out.println("方法名:" + getName(methodInfo.getName_index(), classFile)); System.out.println("方法描述符:" + getName(methodInfo.getDescriptor_index(), classFile)); System.out.println("屬性總數(shù):" + methodInfo.getAttributes_count().toInt()); System.out.println(); } } }
單元測試結(jié)果輸出如圖2.10所示。

圖2.10 方法表解析器單元測試
從輸出的結(jié)果可以看出,該單元測試解析的class文件,有5個方法,訪問權(quán)限都是public,其中有一個方法是靜態(tài)方法;這五個方法的屬性表都只有一個屬性,實(shí)際都是Code屬性;這五個方法的方法名稱分別是<init>、setA、setB、setC和main;還能看到各個方法的方法描述符。
- C++程序設(shè)計(jì)(第3版)
- Java高手真經(jīng)(高級編程卷):Java Web高級開發(fā)技術(shù)
- 程序員數(shù)學(xué):用Python學(xué)透線性代數(shù)和微積分
- Python零基礎(chǔ)快樂學(xué)習(xí)之旅(K12實(shí)戰(zhàn)訓(xùn)練)
- JavaScript:Moving to ES2015
- OpenResty完全開發(fā)指南:構(gòu)建百萬級別并發(fā)的Web應(yīng)用
- Python大學(xué)實(shí)用教程
- 一步一步跟我學(xué)Scratch3.0案例
- Java EE項(xiàng)目應(yīng)用開發(fā)
- Software Architecture with Python
- Pandas 1.x Cookbook
- Android項(xiàng)目實(shí)戰(zhàn):博學(xué)谷
- JavaScript高級程序設(shè)計(jì)(第4版)
- JavaScript程序設(shè)計(jì)基礎(chǔ)教程(慕課版)
- Mastering Android Application Development