类文件结构

类文件结构

目录

  • Class类文件结构
    • 特殊字符串概念
    • 魔数与Class文件的版本
    • 常量池
    • 访问标志
    • 类索引,父类索引与接口索引集合
    • 字段表集合
    • 方法表集合
    • 属性表集合

类文件结构

  • Class文件结构只有两种数据类型:无符号数和表.

无符号数属于基本的数据类型,以u1, u2, u4, u8分别代表1个字节,2个字节,4个字节和8个字节的无符号数,它用来描述数字,索引引用,数量值或者UTF-8编码构成字符串值.
表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯以_info结尾.

整个class文件本质就是一张表:

类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count-1
u2 access_flag 1
u2 this_class 1
u2 super_class 1
u2 interface_count 1
u2 interface interface_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

特殊字符串的概念

  • 全限定名: 把类的全名中的.替换成/,最后再加上;

  • 简单名称: 没有类型和参数修饰的方法或者字段名称.

  • 方法和字段的描述符: 描述符的作用是用来描述字段的数据类型,方法参数列表和返回值.

  • 描述符标识字符含义:

标识字符 含义
B 基本类型byte
C 基本类型char
D 基本类型double
F 基本类型float
I 基本类型int
J 基本类型long
S 基本类型short
Z 基本类型boolean
V 特殊类型void
L 对象类型

魔数与Class文件版本

  • 每个Class文件的头4个字节称为魔数,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的class文件.

  • 紧接魔数后面的4个字节储存的是Class文件的版本号: 第5,6个字节是此版本号(Minor Version),第7和第8个字节是主版本号. JDK的版本号是从45开始的.

常量池

  • 常量池可以理解为Class文件之中的资源仓库,它同时是Class文件关联其他项目最多的数据类型,也是占用Class文件空间最大的数据项目之一.

  • 由于常量池中的常量是不固定的,所以需要在常量池入口放置一项u2类型的数据,代表常量池容量计数值.

  • 常量池中主要储存两大类常量:字面量和符号引用.字面量比较接近Java语言层面的常量概念,如字符串,声明为final常量值等. 而符号引用则属于编译原理方面的概念,主要包含了下面三类常量:

    • 类和接口的全称限定名

    • 字段的名称和描述符

    • 方法的名称和描述符

  • 常量池的项目类型:

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

访问标志

  • access_flags用于识别一些类或者接口层次的访问信息.例如:这个class是类还是接口;是否定义为public类型;是否定义为abstract类型等. 具体标记:
标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final,只有类可设置
ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令新语意
ACC_INTERFACE 0x0200 标识这是一个接口
ACC_ABSTRACT 0x0400 是否为abstact类型, 对于接口或者抽象类来说, 这个标志为真,其他值为假
ACC_SYNTHETIC 0x1000 标识这个类并非由用户代码生成
ACC_ANNOTION 0x2000 标识这是一个注解
ACC_ENUM 0x4000 标识这个一个枚举

类索引,父类索引与接口索引集合

  • 类索引用于确定这个类的全限定名

  • 父类索引用于确定这个类的父类的全限定名

  • 接口索引集合用于描述这个类实现了哪些接口

字段表集合

  • 字段表集合用于描述接口或者类中声明的变量.

  • 字段包括类级变量和实例级变量, 但不包括在方法内的局部变量

  • 字段表结构:

类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 descriptor 1
u2 attributes_count 1
attribute_info attributes attributes_count

方法表集合

  • 方法表结构:
类型 名称 数量
u2 access_flags 1
u2 name_index 1
u2 descriptor 1
u2 attributes_count 1
attribute_info attributes attributes_count
  • 方法表集合结构跟字段表结构大致相同
  • 如果父类分方法没有被子类重写,方法表集合中就不会出现父类方法的信息.

属性表集合

  • Class文件, 字段表, 方法表都可以携带自己的属性表集合, 用于描述特定场景的专有信息.

  • 虚拟机规范预定义的属性

属性名称 使用位置 含义
Code 方法表 Java代码编译成的字节码指令
ConstantValue 字段表 final关键字定义的常量值
Deprecated 类,方法表字段表 被声明为deprecated的方法和字段
Exceptions 方法表 方法抛出的异常
EncloseingMethod 类文件 仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法.
InnerClasses 类文件 内部类列表
LineNumberTable Code属性 Java源码的行号与字节码指令对应的关系
LocalVariableTable Code属性 方法的局部属性描述
StackMapTable Code属性 JDK1.6中新增的属性, 供新的类型检查验证器检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配.
Signature 类,方法表,字段表 用于支持泛型情况下的方法签名, 记录这泛型中的相关信息.
SourceFile 类文件 记录源文件的名称
SourceDebugFile 类文件 储存额外的调试信息
Synthetic 类, 方法表, 字段表 标识方法和字段为编译器生成
LocalVariableTypeTable 为了引入泛型语法之后能够描述泛型参数化类型而添加的
RuntimeVisibleAnnotations 类, 方法表,字段表 为动态注解提供支持, 用于指定哪些注解运行时是可见的
RuntimeInvisibleAnnotations 类, 方法表, 字段表 RuntimeVisibleAnnotations的作用相反
RuntimeVisibleParameterAnnotations 方法表 RuntimeVisibleAnnotations的作用相似
RuntimeInvisibleParameterAnnotations 方法表 RuntimeInvisibleAnnotations的作用相似
AnnotationDefault 方法表 记录注解类的默认值
BootstrapMethods 类文件 用于保存invokedynamic指令引用的引导方法限定符

待续…

分享到