解析Class文件示例

准备

class文件是Java虚拟机唯一可以识别的文件,根据Class文件我们可以完成一个程序的运行,本节文章是本人解析一个基本Class文件的全过程,记录在此,希望能提供给正在前进路上的同学作为辅助作用,下面是我们要解析Class文件必要条件。

代码

以下是一个简单的Java类,一个私有变量,一个公开方法。

public class TestClass {

    private int a;

    public int increment() {

        return a + 1;
    }

}

将这个类编译为Class文件

解析Class文件示例_第1张图片

准备文本编辑器

本人使用Sublime Text打开我们编译后的Class文件,主要目的是对照《Java虚拟机规范》中的Class文件的数据结构,下面是Sublime Text下载的网址。

Sublime Text

使用Sumlime打开Clas文件

解析Class文件示例_第2张图片

《Java虚拟机规范》

我们需要按照Java虚拟机规范中的数据结构,进行Class文件的十六进制码进行解析,所以这里需要按照官网,进行解析,以下是PDF在线链接,本节使用Java8版本。
Java虚拟机规范1.8

打开《Java虚拟机规范》

解析Class文件示例_第3张图片

解析

我们需要知道一个Class文件由哪些数据结构组成,并排列出来,一项数据占几个字节,这些我们都要知道。
我们首先需要记录,这个Class文件的大体结构,Class文件的数据结构及顺序都是需要严格按照《Java虚拟机规范》生成的,找到《Java虚拟机规范》中的 "The Class File Format (Class文件格式)"中的Class结构项。

解析Class文件示例_第4张图片

需要解释的是,这个ClassFile数据结构中的U2、u4分别代表两个字节、四个字节,其对应的右边的英文项,代表着其数据的常量项,Class文件是一定按照这个结构进行构件的,《Java虚拟机规范》中也说明了每一项的描述,本人结合官网整理如下:

解析Class文件示例_第5张图片

这个是本人整理的Class文件的数据结构,有且只有这16项,具体的每一项,本文稍后都有解释。其实Class文件并不复杂,只是Class中的引用比较多,例如constant_pool_info中,这是一个常量池,池中记录着类、方法、字面量等描述符,是相互引用的方式。

javap查看class文件具体结构

使用javap查看文件结构,主要是为了供我们于Class二进制方式进行比对时的一个参照物,以说明我们解读class文件时得出的结论是正确的。其余我们需要确定我们常量池中的顺序以及所对应的常量池名。

javap -v TestClass.class

输出结果

解析Class文件示例_第6张图片

根据javap所输出的数据结构,我们得到了大致的数据结构,剩下的我们需要自行解析,并比对class中的十六进制数进行填写。这里采用yaml文本格式进行填充,yaml格式能很直观的展现出一个对象的数据结构,并且采用这种方式也可以很直接的将解析的值带入。针对我们要解析的class文件,其中____是我们要填充的数据,并且也进行了简单的注释说明字段的含义及所占用的字节。结构如下:

class:
  #魔数 u4
  magic-number: ____
  #小版本号 u2
  minor-version: ____
  #大版本号 u2
  major-version: ____
  #常量池
  constant-pool:
    #常量池总数 u2
    count: ____
    #常量池(数组)
    constants: ____
  #访问标志 u2
  access_flags: ____
  #当前类 u2
  this_class: ____
  #父类 u2
  super_class: ____
  #接口
  interface:
    # u2
    count: ____
    interfaces:
  #字段
  field:
    # u2
    count: ____
    fields: ____
  #方法
  method:
    # u2
    count: ____
    methods: ____
  #属性
  attributes:
    #u2
    count: ____
    attributes: ____

有了大致的结构,我们就可以开始解析之路啦!!

魔数

魔数项提供标识类文件格式的魔术数;它的值为0xCAFEBABE,这个值是固定的,每个文件都有属于自己的魔数,但在class文件中,CAFEBABE就是class文件的魔数,它占用4个字节。

解析Class文件示例_第7张图片

随后将CAFEBABE填入我们的yaml文件中:

解析Class文件示例_第8张图片

小版本号

小版本号占用2个字节,因此,将class文件中的0000转换为十进制为0,所以小版本号为0;

大版本号

。。。

你可能感兴趣的:(classjava)