美文网首页
Java虚拟机(二)—class结构

Java虚拟机(二)—class结构

作者: 小吵闹123 | 来源:发表于2018-11-02 16:37 被阅读17次

    类文件结构

    类文件是一组以8位字节为基础的二进制流,各个数据必须严格按照顺序排列在类文件中,并且只有两种数据类型

    • 无符号数: 描述数字、索引引用、数量值或者UTF-8编码的字符串
    • 表: 由无符号数或其它表作为数据结构的符合数据类型
    名称 类型 数量
    magic u4 1
    minor_version u2 1
    major_version u2 1
    constant_pool_count u2 1
    constant_pool cp_info constant_pool_count-1
    access_flag u2 1
    this_class u2 1
    super_class u2 1
    interfaces_count u2 1
    interfaces u2 1
    fields_count u2 1
    field_info fields fields_count
    methods_count u2 1
    methods methods_info methods_count
    atrributes_count u2 1
    atrributes atrribute_info atrributes_count

    魔数和class文件版本

    每个class文件头4个字节称为魔数(magic),用于确定这个class文件是否能被虚拟机接受,class文件魔数为0xCAFEBABE。

    紧接着魔数后4个字节是class文件版本号,第5和第6字节是次版本号(minor_version),第7和第8字节是主版本号(major_version)

    常量池

    主版本号之后是常量池入口,常量池是class文件结构中与与其它数据关联最多的数据类型。常量池入口有一个u2类型的数据,代表常量池容量计数(constant_pool_count),这个值从1开始,0有特殊作用,表示在特定情况下不引用任何一个常量池项目。

    常量池中主要存放一下两种常量

    • 字面量(Literal): 常量,如文本字符串和被声明为final的常量值等
    • 符号引用(Symbolic Reference):
      • 类和接口的全限定名
      • 字段的名称和描述符
      • 方法的名称和描述符

    访问标记

    常量池之后是访问标记(access_flag),用于识别一些类或接口的访问信息

    标记名称 标记值 含义
    ACC_PUBLIC 0x0001 是否为public
    ACC_FINAL 0x0010 是否为final,只有类可以设置
    ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令,JDK 1.2之后为true
    ACC_INTERFACE 0x0200 是否为接口
    ACC_ABSTRACT 0x0400 是否为abstract类型,接口和抽象类为true,其它为false
    ACC_SYNTHETIC 0x1000 非用户代码产生
    ACC_ANNOTATION 0x2000 是否为注解
    ACC_ENUM 0x4000 是否为枚举

    类索引、父类索引和接口索引集合

    • 类索引(this_class): 用于确定这个类的全限定名
    • 父类索引(super_class)是u2类型: 用于确定这个父类的全限定名
    • 接口索引(interfaces_count): 用来描述这个类实现了哪些接口,是一组u2类型的数据集合

    字段表集合

    • 字段表(field_info): 用于描述接口或类中声明的变量
    • 字段(fields): 包含了类级别变量或实例变量,但不包含方法内部声明的变量

    字段表结构

    名称 类型 数量 说明
    access_flags u2 1 访问限定标记
    name_index u2 1 对常量池引用,字段的简单名字
    descriptor_index u2 1 对常量池引用,字段和方法的描述符
    attributes_count u2 1
    attributes attributes_info 1

    字段访问标志

    |ACC_PUBLIC| 0x0001 | 是否为public|
    |ACC_PRIVATE| 0x0002 | 是否为private|
    |ACC_PROTECTED| 0x0004 | 是否为protected|
    |ACC_STATIC| 0x0008| 是否为static|
    |ACC_FINAL| 0x0010| 是否为final|
    |ACC_VOLATILE| 0x0040| 是否为volitale|
    |ACC_TRANSIENT| 0x0080| 是否为transient|
    |ACC_SYNTHETIC| 0x1000| 是否由编译器自动产生|
    |ACC_ENUM| 0x4000| 是否为枚举|

    方法表集合

    和字段表集合类似

    属性表集合

    属性表(attributes_info)用于描述某些场景专有的信息。

    名称 使用位置 含义
    Code 方法表 Java代码变异成的字节码指令
    ConstantValue 字段表 final关键定义的常量
    Deprecated 类、方法和字段表 被声明为deprecated的方法和字段
    Execeptions 方法表 方法跑出的异常
    InnerClass 类方法 内部类列表
    LineNumberTable Code属性 Java源码的行号与字节指令的对应关系
    LocalVariableTable Code属性 方法的局部变量描述
    SourceFile 类文件 源文件名称
    Synthetic 类、方法和字段表 表示方法或字段为编译器自动生成
    code属性

    Java方法体里的代码被编译器处理后最终变成字节码存在code属性内

    名称 类型 数量 说明
    attribute_name_index u2 1 指向CONSTANT_Utf8_info常量的索引,固定为Code
    attribute_length u4 1 属性值的长度
    max_stack u2 1 操作栈最大深度,虚拟机运行时需要根据这个值来分配栈帧的栈深度
    max_locals u2 1 表示局部变量所需的储存空间,单位是slot,是虚拟机为局部变量分配内存所使用的最小单位(1 slot = 32bit)
    code_length u4 1 字节码的长度,虽然是u4,但是字节码长度不能超过65535
    code u1 code_length 储存字节码
    exception_table_length u2 1
    exception_table exception_info 1
    attribues_count u2 1
    attributes attribute_info attribues_count

    Exception属性

    用于列举出方法中可能抛出的受查异常

    名称 类型 数量 说明
    attribute_name_index u2 1
    attribute_length u4 1 属性值的长度
    number_of_exceptions u2 1
    exception_index_table u2 number_of_exceptions

    LineNumberTable属性

    用于描述Java源代码和字节码行号(偏移量)之间的对应关系,不是运行时必须的属性,如果不生成该属性就无法再抛出异常时返回代码中对应的行号。

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度
    line_number_table_Length u2 1
    line_number_table line_number_info line_number_table_length

    LocalVariableTable属性

    用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,不是运行时必须的属性,如果没有生成所有参数名称都将丢失

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度
    local_variable_table_Length u2 1
    local_variable_table local\ _variable_info local_variable_table_length
    local_variable_info结构
    名称 类型 数量 说明
    start_pc u2 1 这个局部变量声明周期开始时的字节码偏移量
    length u2 1 这个局部变量声明周期开始时的字节码作用范围的长度
    name_index u2 1 指向CONSTANT_Utf8_info常量的索引,代表局部变量的名称
    descriptor_index 1 指向CONSTANT_Utf8_info常量的索引,代表局部变量的描述符
    index 1 u2 表示这个局部变量在栈帧局部变量中slot的位置

    SourceFile属性

    用于记录生成这个class文件源代码的名称,是可选的,如果不生成这个属性,抛出异常时不会显示出错代码的文件名。

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度
    sourcefule_index u2 1 指向CONSTANT_Utf8_info常量的索引,常量值时源码文件的文件名

    ConstantValue属性

    ConstantValue属性的作用是通知虚拟机自动为静态变量赋值,只有被static修饰的变量才能用这个属性

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度
    constant_value_index u2 1 指向常量池的引用

    InnerClasses属性

    InnerClasses属性用于记录内部类与宿主类之间的关联,如果一个类中有内部类,则会生成InnerClass属性。

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度
    nubmber_of_classes u2 1 代表记录多少个内部类信息
    inner_class inner_class_info nubmber_of_classes
    inner_class_info
    名称 类型 数量 说明
    inner_class_info_index u2 1 指向CONSTANT_Class_info常量的索引,代表内部类的符号引用
    outter_class_info_index u2 1 指向CONSTANT_Class_info常量的索引,代表宿主类的符号引用
    inner_name_index u2 1 指向CONSTANT_Utf8_info常量的索引,代表这个内部类的名称,如果是匿名内部类则为0
    inner_name_access_flag u2 1 内部类的访问标志

    Deprecated属性

    表示某个类、字段或方法不再推荐使用

    Synthetic属性

    表示该字段和方法是不是有Java源码直接生成的

    名称 类型 数量 说明
    attribute_name_index u2 1 属性值的索引
    attribute_length u4 1 属性值的长度,值必须为0x00000000

    参考

    • 深入理解Java虚拟机, 周志明

    相关文章

      网友评论

          本文标题:Java虚拟机(二)—class结构

          本文链接:https://www.haomeiwen.com/subject/wsycxqtx.html