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

解析实现的接口

解析完this_class与super_class之后,就可以继续解析获取该class实现的接口总数以及该class实现的所有接口。接口解析器InterfacesHandler的实现如代码清单2-39所示。

代码清单2-39 InterfacesHandler类

public class InterfacesHandler implements BaseByteCodeHandler {

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

    @Override
public void read(ByteBuffer codeBuf, ClassFile classFile) throws Exception {
  // 接口总数interfaces_count
       classFile.setInterfaces_count(new U2(codeBuf.get(), codeBuf.get()));
       int interfaces_count = classFile.getInterfaces_count().toInt();
    // 解析接口表
       U2[] interfaces = new U2[interfaces_count];
       classFile.setInterfaces(interfaces);
       for (int i = 0; i < interfaces_count; i++) {
           interfaces[i] = new U2(codeBuf.get(), codeBuf.get());
       }
   }

}

如代码清单2-39所示,read方法完成接口表的解析。在读取class文件字节缓存时,先顺序读取到interfaces_count,interfaces_count是类实现的接口总数。再根据interfaces_count创建接口表interfaces,接口表的数组长度等于interfaces_count。接口表中的每项都是一个常量索引,指向常量池表中CONSTANT_Class_info结构的常量。

将解析器注册到ClassFileAnalysiser,然后编写单元测试。由于接口表中的每项是指向常量池表中CONSTANT_Class_info结构的常量,因此,我们可以在单元测试中,根据CONSTANT_Class_info的name_index获取到对应的CONSTANT_Utf8_info常量,拿到接口的类型名称。单元测试如代码清单2-40所示。

代码清单2-40 接口解析器单元测试

public class InterfacesHandlerTest {

    @Test
    public void testInterfacesHandlerHandler() throws Exception {
        ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("InterfacesHandler.class");
        ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf);
        System.out.println("接口总数:" + classFile.getInterfaces_count().toInt());
        if (classFile.getInterfaces_count().toInt() == 0) {
            return;
        }
        U2[] interfaces = classFile.getInterfaces();
// 遍历接口表
        for (U2 interfacesIndex : interfaces) {
      // 根据索引从常量池中取得一个CONSTANT_Class_info常量
            CONSTANT_Class_info interfaces_class_info =
                        (CONSTANT_Class_info) classFile.getConstant_pool()
                                              [interfacesIndex.toInt() - 1];
       // 根据CONSTANT_Class_info的name_index从常量池取得一个
//  CONSTANT_Utf8_info常量
           CONSTANT_Utf8_info interfaces_class_name_info =
                     (CONSTANT_Utf8_info) classFile.getConstant_pool()
                      [interfaces_class_info.getName_index().toInt() - 1];
            System.out.println(interfaces_class_name_info);
        }
    }

}

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

图2.8 接口解析器单元测试

从结果可以看出,该class文件实现的接口总数为1,实现的接口为BaseByteCodeHandler。