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

解析版本号

class文件结构的版本号分为主版本号和副版本号,它们共同构成class文件格式的版本号[1]。比如一个class文件的主版本号为56,副版本号为0,那么这个class文件结构的版本号就是52.0。副版本号在前,主版本号在后,分别占两个字节。

版本号解析器的职责就是从class文件字节缓存中读取出副版本号和主版本号。按顺序读取,先读取两个字节的副版本号,再读取两个字节的主版本号。版本号解析器的实现如代码清单2-8所示。

代码清单2-8 版本号解析器

public class VersionHandler implements BaseByteCodeHandler {
// 版本号解析器排在魔数解析器的后面
    @Override
    public int order() {
        return 1;
    }

    @Override
    public void read(ByteBuffer codeBuf, ClassFile classFile) throws Exception {
        // 读取副版本号
U2 minorVersion = new U2(codeBuf.get(), codeBuf.get());
        classFile.setMinor_version(minorVersion);
        // 读取主版本号
U2 majorVersion = new U2(codeBuf.get(), codeBuf.get());
        classFile.setMagor_version(majorVersion);
    }

}

class文件格式的各版本号与JDK版本的对应关系如表2-9所示。

表2-9 各版本的对应关系

现在我们随便找个class文件来编写单元测试,验证框架是否能正确解析出该class文件的魔数和版本号,单元测试如代码清单2-10所示。

代码清单2-10 魔数与版本号解析器单元测试

public class MagicAndVersionTest {

    @Test
public void testMagicAndVersionHandler() throws Exception {
  // 将class文件读取到ByteBuffer
        ByteBuffer codeBuf = ClassFileAnalysisMain.readFile("RecursionAlgorithmMain.class");
    // 解析class文件
        ClassFile classFile = ClassFileAnalysiser.analysis(codeBuf);
        System.out.println(classFile.getMagic().toHexString());  // 打印模数
        System.out.println(classFile.getMinor_version().toInt());  // 打印副版本号
        System.out.println(classFile.getMagor_version().toInt());  // 打印主版本号
    }

}

程序运行结果如图2.3所示。

图2.3 魔数与版本号解析器单元测试


注释:

[1] 《Java虚拟机规范》Java SE8版本ClassFile结构