Class文件结构

前置概念

Class文件的基本数据类型是由无符号数和表组成的。

  • 无符号数是基本类型,可取的值有 u1,u2,u4,u8分别代表了1,2,4,8个字节的无符号数,这种数据可以用来表述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。
  • 表则相当于一种数据结构,表中的每一项可以是一种基本类型,也可以是另一个表。所有的表都习惯性的以"_info"结尾。
  • 全限定名,也就是一个类的全路径
  • 简单名,例如一个类中的add()方法,它的简单名就是add
  • 描述符
    • 字段描述符,用来描述字段的类型。例如"S",代表short类型,"I"代表int类型等。
    • 方法描述符,用来描述方法的参数列表和返回值。例如”(IS)I“则代表这个方法需要两个参数,一个int,一个short,返回值是一个int类型。

一、魔数和Class文件的版本号

  • ”CAFEBABE“
    • 类型:u2;Class文件的开头4字节为固定的”CAFEBABE“表明当前的文件是一个Class文件
  • minor_version
    • 类型:u2;当前class文件的次版本号
  • major_version
    • 类型:u2;当前class文件的主版本号

次版本号和主版本号规定了当前的class文件可以被哪个版本的虚拟机所执行,同时虚拟机加载class文件的时候也会检查这三个属性。

二、常量池

  • constant_pool_count

    • 类型:u2;常量池中的常量数量,由于常量池中的常量数量不确定,所以需要这个字段告诉虚拟机当前类中有多少个常量,而后则是这一个一个的常量,每个常量的类型可能不一致,但都会明确自己的数据结构和占用空间。
  • constant_pool

    • 类型:cp_info;常量池中的一项常量,可以是下面14中类型的其中一种。

      标志类型描述
      1CONSTANT_Utf8_infoUTF8编码的字符串
      3CONSTANT_Integer_info整型字面量
      4CONSTANT_Float_info浮点型字面量
      5CONSTANT_Long_info长整型字面量
      6CONSTANT_Double_info双精度浮点型字面量
      7CONSTANT_Class_info类或接口的符号引用
      8CONSTANT_String_info字符串类型字面量
      9CONSTANT_Fieldref_info字段的符号引用
      10CONSTANT_Methodref_info类中方法的符号引用
      11CONSTANT_InterfaceMethodref_info接口中方法的符号引用
      12CONSTANT_NameAndType_info字段或方法的部分符号引用
      15CONSTANT_MethodHandle_info表示方法句柄
      16CONSTANT_MethodType_info标识方法类型
      18CONSTANT_InvokeDynamic_info表示一个动态方法调用点

常量池里面存放着当前这个类的一些元数据,也就是一些基本资料。例如字面量、符号引用等,其中字面量比较好理解,就是文本字符串或者是常量值等(就是直接量,自身描述自身,"ss"就是表示一个字符串"ss")。符号引用则比较复杂一点,它可以是类和接口的全限定名、字段的名称描述、方法的名称和描述。

三、访问标志

  • access_flags
    • 类型:u2;访问标志,用于表明当前这个类或者接口的访问信息,例如:它是类还是接口,是不是public的,是不是abstract的,是不是final的等。

四、继承体系描述

  • this_class
    • 类型:u2;类索引,用于确定这个类的全限定名,u2的数据代表了常量池中一个常量的索引下标,对应的常量就描述了这个类的全限定名。
  • super_class
    • 类型:u2;父类索引,用于确定父类的全限定名,u2的数据代表了常量池中一个常量的索引下标,对应的常量就描述了这个类的全限定名。
  • interfaces_count
    • 类型:u2;这个类实现的接口的数量;u2可以表示到65535,也就是类能实现的最大的接口数量。
  • interfaces
    • 类型:u2;接口索引,用于确定接口的全限定名,u2的数据代表了常量池中一个常量的索引下标,对应的常量就描述了这个接口的全限定名。

五、字段表集合

  • fields_count

    • 类型:u2;表示当前类变量或实例变量的数量。
  • field

    • 类型:field_info;一种描述当前字段的数据结构,可以包含的信息有,作用域、是否被static修饰、是否final、是否volatile、是否transient、字段的数据类型、字段名称。

      名称描述类型
      access_flag字段访问标志u2
      name_index常量池中对应的字段名称的索引u2
      descriptor_index该字段描述符在常量池中的索引,例如指向常量池中的常量: S,就说明这个字段是 short类型的。u2
      attributes_coun字段额外属性的数量u2
      attributes属性表attrbute_info

六、方法表集合

  • method_count

    • 类型:u2;类中方法的数量
  • methods

    • 类型:method_info;方法表

    • 名称描述类型
      access_flags方法访问标志u2
      name_index常量池中对应的方法简单名索引u2
      descriptor_index方法描述符在常量池中的索引u2
      attributes_count属性数量u2
      attributes属性表,预置了多种定义好的属性attribute_info

七、属性表集合

前面的字段表和方法表中都有出现属性表,在class文件、字段表放发表都可以携带自己的属性表集合,用于描述某些常见的专有信息。与其他数据项目不一样,属性表集合的要求很宽松,只要属性名称不重复即可。我们编写的方法,里面的逻辑代码产生的字节码指令就放在方法表的属性表中,属性名字叫做”code“。一个标准的属性应该符合下面的这种结构。

类型名称描述
u2attribute_name_index属性名称在常量池中的索引
u4attribute_length属性长度,包含了当前两个属性所占长度。
u1info属性体,可以自由发挥

以code属性为例

类型名称描述
u2attribute_name_index同上
u4attribute_length同上
u2max_stack操作数栈,最大深度
u2max_locals存储局部 变量所需空间Slot个数
u4code_length指令条数
u1code指令,u1=256,则指令最多有256种
u2exception_table_length
exception_infoexception_table
u2attrbute_count属性个数
attribute_infoattributes属性

Q.E.D.