- Java虛擬機(jī)字節(jié)碼:從入門(mén)到實(shí)戰(zhàn)
- 吳就業(yè)
- 1087字
- 2021-01-08 19:08:27
解析字段表
同一個(gè)Class文件中,不會(huì)存在兩個(gè)相同的字段。相同指定的是字段名與類(lèi)型描述符都相同。字段結(jié)構(gòu)與Class文件結(jié)構(gòu)一樣,都有訪問(wèn)標(biāo)志項(xiàng),但兩者的訪問(wèn)標(biāo)志項(xiàng),在訪問(wèn)權(quán)限和屬性上有些區(qū)別。參照《Java虛擬機(jī)規(guī)范》,字段中的訪問(wèn)權(quán)限和屬性標(biāo)志如表2-41所示。
表2-41 字段訪問(wèn)權(quán)限與屬性標(biāo)志


字段的結(jié)構(gòu)如表2-42所示。
表2-42 字段的結(jié)構(gòu)

其中,access_flags是字段的訪問(wèn)標(biāo)志,name_index是字段名稱(chēng),descriptor_index是字段的類(lèi)型描述符。字段結(jié)構(gòu)與方法結(jié)構(gòu)、Class文件結(jié)構(gòu)都有屬性表attributes,屬性表的屬性個(gè)數(shù)可以是0個(gè)或多個(gè)。屬性的通用結(jié)構(gòu)如表2-43所示。
表2-43 屬性的通用結(jié)構(gòu)

關(guān)于屬性,我們先了解屬性的通用結(jié)構(gòu),實(shí)現(xiàn)屬性的初步解析,讓字段解析器能夠完成字段的解析工作,至于屬性info是什么暫時(shí)先不關(guān)心。
創(chuàng)建字段結(jié)構(gòu)對(duì)應(yīng)的Java類(lèi)FieldInfo,如代碼清單2-44所示。
代碼清單2-44 FieldInfo類(lèi)
public class FieldInfo { private U2 access_flags; private U2 name_index; private U2 descriptor_index; private U2 attributes_count; private AttributeInfo[] attributes; }
創(chuàng)建屬性結(jié)構(gòu)對(duì)應(yīng)的Java類(lèi)AttributeInfo,如代碼清單2-45所示。
代碼清單2-45 AttributeInfo類(lèi)
public class AttributeInfo { private U2 attribute_name_index; private U4 attribute_length; private byte[] info; }
創(chuàng)建字段表解析器FieldHandler,實(shí)現(xiàn)字段表的解析。字段結(jié)構(gòu)的屬性表的解析工作也由字段表解析器完成。解析流程如下:
1、先從class文件字節(jié)緩存中讀取到字段總數(shù),根據(jù)字段總數(shù)創(chuàng)建字段表;
2、循環(huán)解析出每個(gè)字段;
3、解析字段的屬性表時(shí),先解析獲取到屬性總數(shù),再根據(jù)屬性總數(shù)創(chuàng)建屬性表;
4、使用通用屬性結(jié)構(gòu)循環(huán)解析出字段的每個(gè)屬性;
5、解析屬性時(shí),先解析出attribute_name_index,再解析attribute_length獲取屬性info的長(zhǎng)度,根據(jù)長(zhǎng)度讀取指定長(zhǎng)度的字節(jié)數(shù)據(jù)存放到屬性的info字段。
字段表解析器的實(shí)現(xiàn),如代碼清單2-46所示。
代碼清單2-46 FieldHandler類(lèi)
public class FieldHandler implements BaseByteCodeHandler { @Override public int order() { // 排在接口解析器的后面 return 6; } @Override public void read(ByteBuffer codeBuf, ClassFile classFile) throws Exception { // 讀取字段總數(shù) classFile.setFields_count(new U2(codeBuf.get(), codeBuf.get())); int len = classFile.getFields_count().toInt(); if (len == 0) { return; } // 創(chuàng)建字段表 FieldInfo[] fieldInfos = new FieldInfo[len]; classFile.setFields(fieldInfos); // 循環(huán)解析出每個(gè)字段 for (int i = 0; i < fieldInfos.length; i++) { // 解析字段 fieldInfos[i] = new FieldInfo(); // 讀取字段的訪問(wèn)標(biāo)志 fieldInfos[i].setAccess_flags(new U2(codeBuf.get(), codeBuf.get())); // 讀取字段名稱(chēng) fieldInfos[i].setName_index(new U2(codeBuf.get(), codeBuf.get())); // 讀取字段類(lèi)型描述符索引 fieldInfos[i].setDescriptor_index(new U2(codeBuf.get(), codeBuf.get())); // 讀取屬性總數(shù) fieldInfos[i].setAttributes_count(new U2(codeBuf.get(), codeBuf.get())); // 獲取字段的屬性總數(shù) int attr_len = fieldInfos[i].getAttributes_count().toInt(); if (attr_len == 0) { continue; } // 創(chuàng)建字段的屬性表 fieldInfos[i].setAttributes(new AttributeInfo[attr_len]); // 循環(huán)解析出每個(gè)屬性,先使用通用屬性結(jié)構(gòu)解析每個(gè)屬性 for (int j = 0; j < attr_len; j++) { // 解析字段的屬性 fieldInfos[i].getAttributes()[j] .setAttribute_name_index(new U2(codeBuf.get(),codeBuf.get())); // 獲取屬性info的長(zhǎng)度 U4 attr_info_len = new U4(codeBuf.get(), codeBuf.get(), codeBuf.get(), codeBuf.get()); fieldInfos[i].getAttributes()[j].setAttribute_length(attr_info_len); // 解析info byte[] info = new byte[attr_info_len.toInt()]; codeBuf.get(info, 0, attr_info_len.toInt()); fieldInfos[i].getAttributes()[j].setInfo(info); } } } }
編寫(xiě)將字段的訪問(wèn)標(biāo)志access_flags轉(zhuǎn)為字符串輸出的工具類(lèi)FieldAccessFlagUtils,如代碼清單2-47所示。
代碼清單2-47 access_flags轉(zhuǎn)字符串工具類(lèi)
public class FieldAccessFlagUtils { private static final Map<Integer, String> fieldAccessFlagMap = new HashMap<>(); static { fieldAccessFlagMap.put(0x0001, "public"); fieldAccessFlagMap.put(0x0002, "private"); fieldAccessFlagMap.put(0x0004, "protected"); fieldAccessFlagMap.put(0x0008, "static"); fieldAccessFlagMap.put(0x0010, "final"); fieldAccessFlagMap.put(0x0040, "volatile"); fieldAccessFlagMap.put(0x0080, "transient"); fieldAccessFlagMap.put(0x1000, "synthtic"); fieldAccessFlagMap.put(0x4000, "enum"); } /** * 獲取16進(jìn)制對(duì)應(yīng)的訪問(wèn)標(biāo)志和屬性字符串表示 (僅用于類(lèi)的訪問(wèn)標(biāo)志) * * @param flag字段的訪問(wèn)標(biāo)志 * @return */ public static String toFieldAccessFlagsString(U2 flag) { final int flagVlaue = flag.toInt(); StringBuilder flagBuild = new StringBuilder(); fieldAccessFlagMap.keySet() .forEach(key -> { if ((flagVlaue & key) == key) { flagBuild.append(fieldAccessFlagMap.get(key)).append(","); } }); return flagBuild.length() > 0 && flagBuild.charAt(flagBuild.length() - 1) == ',' ? flagBuild.substring(0, flagBuild.length() - 1) : flagBuild.toString(); } }
字段表解析器編寫(xiě)完成,我們先將字段解析器注冊(cè)到ClassFileAnalysiser,再編寫(xiě)單元測(cè)試。編寫(xiě)單元測(cè)試用于驗(yàn)證字段解析器是否能夠正確完成字段表地解析。編寫(xiě)單元測(cè)試要求將解析后的所有字段的名稱(chēng)、類(lèi)型、以及字段的訪問(wèn)標(biāo)志轉(zhuǎn)為字符串打印出來(lái),以驗(yàn)證結(jié)果是否正確。字段表解析器單元測(cè)試如代碼清單2-48所示。
代碼清單2-48 字段表解析器單元測(cè)試
public class FieldHandlerTest { 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 testFieldHandlerHandler() throws Exception { ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("Builder.class"); ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf); System.out.println("字段總數(shù):" + classFile.getFields_count().toInt()); System.out.println(); FieldInfo[] fieldInfos = classFile.getFields(); // 遍歷字段表 for (FieldInfo fieldInfo : fieldInfos) { System.out.println("訪問(wèn)標(biāo)志和屬性:" + FieldAccessFlagUtils .toFieldAccessFlagsString(fieldInfo.getAccess_flags())); System.out.println("字段名:" + getName(fieldInfo.getName_index(), classFile)); System.out.println("字段的類(lèi)型描述符:" + getName(fieldInfo.getDescriptor_index(), classFile)); System.out.println("屬性總數(shù):" + fieldInfo.getAttributes_count().toInt()); System.out.println(); } } }
單元測(cè)試結(jié)果輸出如圖2.9所示。

圖2.9 字段表解析器單元測(cè)試
從結(jié)果輸出可以看出,該class有三個(gè)字段,訪問(wèn)權(quán)限都是private的,字段名分別是a、b、c,并且類(lèi)型描述符都是“I”,即字段的類(lèi)型都是整型。
- Learn to Create WordPress Themes by Building 5 Projects
- Unity Virtual Reality Projects
- Elastic Stack應(yīng)用寶典
- GitLab Repository Management
- Blockly創(chuàng)意趣味編程
- SSM輕量級(jí)框架應(yīng)用實(shí)戰(zhàn)
- Apache Mahout Clustering Designs
- OpenCV Android Programming By Example
- 超簡(jiǎn)單:用Python讓Excel飛起來(lái)(實(shí)戰(zhàn)150例)
- Visual C++程序設(shè)計(jì)與項(xiàng)目實(shí)踐
- Get Your Hands Dirty on Clean Architecture
- JavaEE架構(gòu)與程序設(shè)計(jì)
- Sitecore Cookbook for Developers
- Python全棧開(kāi)發(fā):數(shù)據(jù)分析
- Jenkins 2.x實(shí)踐指南