官术网_书友最值得收藏!

解析class文件的訪問標志

Class文件結構中的訪問標志項access_flags是用U2類型存儲的,也就是2個字節。用某個bit位的值是否為1判斷該類或接口的訪問權限、屬性。訪問標志與類或接口的訪問權限、屬性的映射如表2-33所示。

表2-33 類訪問權限和屬性修飾符標志

如何判斷一個類設置了表2-33中的哪些標志呢?首先從Class文件字節緩存中讀取到access_flags的值,再將access_flags轉為int類型,將轉換后的值“算術與”上各個標志的值,判斷結果是否等于這個標志的值。如代碼清單2-34所示。

代碼清單2-34 獲取Class文件的access_flags字符串表示

public class ClassAccessFlagUtils {

    private static final Map<Integer, String> classAccessFlagMap = new HashMap<>();

    static {
         // 公有類型
         classAccessFlagMap.put(0x0001, "public");
         // 不允許有子類
         classAccessFlagMap.put(0x0010, "final");
         classAccessFlagMap.put(0x0020, "super");
         // 接口
         classAccessFlagMap.put(0x0200, "interface");
         // 抽象類
         classAccessFlagMap.put(0x0400, "abstract");
         // 該class非java代碼編譯后生成
         classAccessFlagMap.put(0x1000, "synthetic");
         // 注解類型
         classAccessFlagMap.put(0x2000, "annotation");
         // 枚舉類型
         classAccessFlagMap.put(0x4000, "enum");
    }

    /**
     * 獲取16進制對應的訪問標志字符串表示 (僅用于類的訪問標志)
     *
     * @param flag訪問標志
     * @return
     */
    public static String toClassAccessFlagsString(U2 flag) {
        final int flagVlaue = flag.toInt();
        StringBuilder flagBuild = new StringBuilder();
        classAccessFlagMap.keySet()
                .forEach(key -> {
                    if ((flagVlaue & key) == key) {
                        flagBuild.append(classAccessFlagMap.get(key)).append(",");
                    }
                });
        return flagBuild.length() > 0 && flagBuild.charAt(flagBuild.length() - 1) == ',' ?
                       flagBuild.substring(0, flagBuild.length() - 1)  : flagBuild.toString();
    }

}

現在我們來實現class文件訪問標志解析器AccessFlagsHandler,并將AccessFlagsHandler解析器交給ClassFileAnalysiser管理。AccessFlagsHandler的排序值設置為3,即放在常量池解析器之后,約定在常量池解析器解析完成之后再到訪問標志解析器解析。AccessFlagsHandler的實現如代碼清單2-35所示。

代碼清單2-35 AccessFlagsHandler解析器

public class AccessFlagsHandler implements BaseByteCodeHandler {

    @Override
    public int order() {
        return 3;
    }

    @Override
    public void read(ByteBuffer codeBuf, ClassFile classFile) throws Exception {
        classFile.setAccess_flags(new U2(codeBuf.get(), codeBuf.get()));
    }

}

最后編寫單元測試,驗證class文件訪問標志解析器是否能正常完成解析。在單元測試中,調用ClassAccessFlagUtils工具類的toClassAccessFlagsString方法將訪問標志輸出為字符串。如代碼清單2-36所示。

代碼清單2-36 訪問標志解析器單元測試

public class AccessFlagsHandlerTest {

    @Test
    public void testAccessFlagsHandlerHandler() throws Exception {
        ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("RecursionAlgorithmMain.class");
        ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf);
    // 獲取訪問標志
        U2 accessFlags = classFile.getAccess_flags();
    // 輸出為字符串
       System.out.println(ClassAccessFlagUtils.toClassAccessFlagsString(accessFlags));
    }

}

單元測試輸出結果如圖2.5所示。

圖2.5 訪問標志解析器單元測試

主站蜘蛛池模板: 高密市| 石家庄市| 琼结县| 永福县| 洛宁县| 额济纳旗| 莎车县| 滁州市| 铅山县| 冕宁县| 英山县| 汕尾市| 朝阳区| 海安县| 滕州市| 绿春县| 龙口市| 边坝县| 景宁| 广水市| 婺源县| 镇赉县| 黔南| 兴仁县| 宁德市| 宁河县| 巨鹿县| 崇阳县| 同心县| 图片| 公主岭市| 新郑市| 资兴市| 尚义县| 茌平县| 常熟市| 黔西县| 得荣县| 德令哈市| 建湖县| 馆陶县|