Java虚拟机字节码:从入门到实战
上QQ阅读APP看书,第一时间看更新

解析this与super

在Class文件结构中,紧挨着访问标志access_flags项的是this_class和super_class这两项,也都是U2类型。this_class存储的是常量池中某项常量的索引,super_class要么为0,要么也是存储常量池中某项常量的索引[1]。this_class和super_class指向的常量必须是一个CONSTANT_Class_info结构的常量。

只有Object类的super_class可以为0,接口的super_class指向常量池中Object类的CONSTANT_Class_info常量。

this_class与super_class的解析器实现非常简单,如代码清单2-37所示。

代码清单2-37 this_class与super_class解析器

public class ThisAndSuperClassHandler implements BaseByteCodeHandler {

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

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

}

由于该项目已经完成了常量池的解析,在解析获取到this_class与super_class之后,我们就可以先根据this_class的值到常量池取得对应的CONSTANT_Class_info常量,再从取得的CONSTANT_Class_info常量中获取该常量的name_index的值,最后根据name_index再回到常量池中取得对应的CONSTANT_Utf8_info常量,这样就能获取到具体的类名了。该过程描述如图2.6所示。

图2.6 获取this_class指向的类名

现在我们编写单元测试验证this与super解析器。为了直观的显示解析结果,我们需要在单元测试用例中,将解析后的this_class与super_class指向的CONSTANT_Class_info常量转为CONSTANT_Utf8_info常量,直接输出字符串类名。如代码清单2-38所示。

代码清单2-38 this与super解析器单元测试

public class ThisAndSuperHandlerTest {

    @Test
    public void testThisAndSuperHandlerHandler() throws Exception {
        ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("RecursionAlgorithmMain.class");
        ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf);
     // this_class
        U2 this_class = classFile.getThis_class();
// 根据this_class到常量池获取CONSTANT_Class_info常量
// 由于常量池的索引是从1开始的,所以需要将索引减1取得数组下标
        CONSTANT_Class_info this_class_cpInfo =
(CONSTANT_Class_info) classFile.getConstant_pool()[this_class.toInt() - 1];

        CONSTANT_Utf8_info this_class_name= (CONSTANT_Utf8_info)
                             classFile.getConstant_pool()
                             [this_class_cpInfo.getName_index().toInt()-1];
        System.out.println(this_class_name);
     // super_class
        U2 super_class = classFile.getSuper_class();
        CONSTANT_Class_info super_class_cpInfo = (CONSTANT_Class_info)
                             classFile.getConstant_pool() [super_class.toInt() - 1];

        CONSTANT_Utf8_info supor_class_name = (CONSTANT_Utf8_info)
                            classFile.getConstant_pool()
                            [super_class_cpInfo.getName_index().toInt()-1];
        System.out.println(supor_class_name);
    }

}

单元测试结果输出如图2.7所示。

图2.7 this与super解析器单元测试

从输出的结果可以看出,该class文件的类名为RecursionAlgorithmMain,父类的类名为Object。


注释:

[1] 常量池索引都是从1开始的,0就表示不使用