JVM-class文件详解(官方直译)含脑图

获取脑图方式请看最下面!
在这里插入图片描述

JVM

类文件(Class文件)结构

ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

magic u4

  • value:0xCAFEBABE

minor_version u2

  • 0000 暂时不用这两个字节

major_version u2

  • 0034 表示版本号为52 表示jdk1.8

constant_pool_count u2

  • value:0025 对应10进制397代表常量池中39个常量

constant_pool[constant_pool_count-1] cp_info 常量池,有tag,info[] info[]的值根据tag的值变化而变化,后面0X…表示tag的值

cp_info {
u1 tag;
u1 info[];
}

  • CONSTANT_Utf8_info u1+u2+u1*length 0x01

    • tag u1:1
    • length u2 bytes中的字节数组长度(不是结果字符串的长度)
    • bytes u1 bytes数组包含字符串的字节。
  • CONSTANT_Integer_info u1+u4 0x03

    • tag u1:3
    • bytes u4 按照高位在前存储的int值,由ASCII转换成16进制获得
  • CONSTANT_float_info u1+u4 0x04

    • tag u1:4
    • bytes u4 按照高位在前存储的float值,由ASCII转换成16进制获得(IEEE 754 floating-point single format)
  • CONSTANT_Long_info u1+u8 0x05

    • tag u1:5
    • high_bytes u4
    • low_bytes u4
  • CONSTANT_Double_info u1+u8 0x06

    • tag u1:6
    • high_bytes u4
    • low_bytes u4
  • CONSTANT_class_info u1+u2 0x07

    • tag u1:7
    • name_index u2 指向权限定名常量池utf8的索引
  • CONSTANT_String_info u1+u2 0x08

    • tag u1:8
    • string_index u2 指向CONSTANT_Utf8_info的索引
  • CONSTANT_Fieldref_info u1+u2+u2 0x09

    • tag u1 :9
    • class_index u2 可以是class类型也可以是接口类型,指向常量池中的有效索引,类型是CONSTANT_Class_info结构
    • name_and_type_index u2 指向字段描述符 CONSTANT_NameAndType_info的索引项(请参考字段描述符)
  • CONSTANT_Methodref_info u1+u2+u2 0x0a

    • tag u1:10
    • class_index u2 必须是class类型,不是接口类型,
    • name_and_type_index u2 指向方法描述符CONSTANT_NameAndType_info的索引项(请参考方法描述符)如果方法名以’<’(’\u003c’)开头,名字必须是特殊的名字(实例初始化会用到),返回类型必须是void
  • CONSTANT_Interface_Methodref_info u5 0x0b

    • tag u1:11
    • class_index u2 必须是接口类型
    • name_and_type_index u2 指向名称及类型描述 符CONSTANT_NameAndType_info的索引项
  • CONSTANT_NameAndType_info u5 0x0c

    • tag u1:12

    • name_index u2 指向该字段或方法名称的CONSTANT_Utf8_info索引

      Class文件中变量,方法的名字以非限定名的形式保存的,简单讲就是单纯的变量名或方法名,是不能包含./[;等ASCII字符的。但有个例外

    • descriptor_index u2 指向CONSTANT_Utf8_info结构,代表一个验证的字段描述符或方法描述符

  • CONSTANT_MethodHandle_info u5 0x0f

    • tag u1 :15

    • reference_kind u2 决定方法类型,值必须是0- 9,该值表示方法句柄的字节码行为

    • reference_index u2 值必须是常量池的有效索引

      • 1.reference_kind=1||2||3||4,指向CONSTANT_Fieldref_info索引

      • 2.reference_kind=5||8,指向CONSTANT_Methodref_info索引

      • 3.reference_kind=6||7

        • 类文件版本<52: 指向CONSTANT_Methodref_info索引
        • 类文件版本>=52: 指向CONSTANT_Methodref_info或者CONSTANT_InterfaceMethodref_info索引
      • 4.reference_kind=9,指向CONSTANT_InterfaceMethodref_info索引

      • 5.reference_kind=8,指向CONSTANT_Methodref_info结构必须是方法

  • CONSTANT_MethodType_info u3 0x10

    • tag u1 :16
    • descriptor_index u2 值必须是常量池的有效索 引,常量池在该索引的项必须是CONSTANT_ Utf8_info结构,表示该方法的描述符
  • CONSTANT_InvokeDynamic_info u5 0x12

    • tag u1 :18
    • bootstrap_method_attr_index u2 当前Class文 件中引导方法表的bootstrap_methods[]数组的 有效索引
    • name_and type_index u2 指向名称及类型描述 符CONSTANT_NameAndType_info的索引项

access_flags u2

  • ACC_PUBLIC 0001可以被包的类访问
  • ACC_FINAL 0010 不允许有子类
  • ACC_SUPER 0020 当用到invokespecial指令 时,需要特殊处理的父类方法
  • ACC_INTEFACE 0200 标识定义的是接口而不 是类
  • ACC_ABSTRACT 0400 不能被实例化,抽象
  • ACC_ANNOTATION 2000 标识注解类型
  • ACC_ENUM 4000 标识枚举类型
  • ACC_SYNTHETIC 1000 标识这个类是否是用户 代码生成。0表示由用户代码生成

this_class u2 :指向一个常量池,一般都指向CONSTANT_class_info类型

super_class u2:指向一个常量池,一般都指向CONSTANT_class_info类型

interfaces_count u2:记录接口的数量,如果为0则不出现interfaces类型

interfaces[interfaces_count] u2:记录具体的接口指向,指向一个常量池对象,一般都指向CONSTANT_class_info类型

fields_count u2:记录字段的数量,如果为0则不出现fields类型

fields[fields_count] field_info:字段表集合

  • access_flags u2:字段访问标志

    • ACC_PUBLIC 0x0001
    • ACC_PRIVATE 0x0002
    • ACC_PROTECTED 0x0004
    • ACC_STATIC 0x0008
    • ACC_FINAL 0x0010
    • ACC_VOLATILE 0x0040
    • ACC_TRANSIENT 0x0080
    • ACC_SYNTHETIC 0x1000 标志指示此字段是由编译器生成的,不会出现在源代码中。
    • ACC_ENUM 0x4000 枚举类型
  • name_index u2: 字段名称索引,指向CONSTANT_Utf8_info索引

  • descriptor_index u2:描述符索引,指向CONSTANT_Utf8_info索引

    • 字段描述符如何表示

      • B byte 字节型
      • C char 字符型
      • I int 整型
      • F float 浮点型
      • S short 短整型
      • J long 长整型
      • D double 双精度浮点型
      • Z boolean 布尔型
      • L+对象全限定名 对象类型,如:String Ljava/lang/String
      • [+基本类型符合 数组类型,如int[] [I
      • V void 无类型
  • attributes_count u2:属性个数

  • attributes[attributes_count]attribute_info->ConstantValue_attribute 字段表集合

    • attribute_name_index u2:属性名称索引,指向CONSTANT_Utf8_info 结构中的“ConstantValue”
    • attribute_length u2:值必须是2
    • constant_value_index:常量池条目索引必须适合该field

methods_count u2:记录方法的数量,如果是类是一定存在的,如果是接口methods_count可能存在为0,enum 最少4(有默认方法)

methods[methods_count] method_info 方法集合

  • access_flags u2:字段访问标志

    • ACC_PUBLIC 0x0001
    • ACC_PRIVATE 0x0002
    • ACC_PROTECTED 0x0004
    • ACC_STATIC 0x0008
    • ACC_FINAL 0x0010
    • ACC_SYNCHRONIZED 0x0020
    • ACC_BRIDGE 0x0040
    • ACC_VARARGS 0x0080
    • ACC_NATIVE 0x0100
    • ACC_ABSTRACT 0x0400
    • ACC_STRICT 0x0800
    • ACC_SYNTHETIC 0x1000 标志指示此字段是由编译器生成的,不会出现在源代码中。
  • name_index u2:方法名称索引,指向CONSTANT_Utf8_info索引的 or or 有效的非限定名称

  • descriptor_index u2 方法描述索引(返回参数索引),指向CONSTANT_Utf8_info索引

  • attributes_count u2 方法中属性个数

  • attributes attribute_info []

    • Code 执行方法 code_attribute_info

      • attribute_name_index u2 属性名索引,指向CONSTANT_Utf8_info中的“Code”

      • attribute_length u4 属性字节长度,不包括前6字节

      • max_stack u2 操作数栈的最大深度

      • max_locals u2 局部变量的最大数目,包含传入参数的局部变量

        • long或double类型的值的最大局部变量索引是max_locals-2,max_locals-1是任何其他类型的值的最大局部变量索引
      • code_length u4 指令长度,表示代码数组中的字节数,必须大于0 小于65536

      • code[code_length] u1*code_length 指令集合

      • exception_table_length 异常计数 u1

      • exception_table[exception_table_length] 异常集合 u8*exception_table_length

        • start_pc u2 开始指令地址
        • end_pc u2 结束指令地址
        • handler_pc u2 异常处理指令地址
        • catch_type u2 异常类型,指向CONSTANT_Class_info中catch时抛出的异常类
      • attributes_count u2 Code结构内属性数

      • attributes attronites_info Code结构体内属性集合

        • LinaNumberTable 源码与指令关系 LinaNumberTable_info

          • attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LineNumberTable”

          • attribute_length u4 属性长度,需要去掉初始的6字节

          • line_number_table_length u2 源码指令关系表计数,表示LinaNumberTable的个数

          • line_number_table[line_number_table_ length] u4*line_number_table_length 源码指令关系表数组

            • stact_pc u2 开始字节码指令地址
            • line_number u2 源码行号
        • LocalVariableTable 局部变量描述

          • attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LocalVariableTable”

          • attribute_length u4 属性长度,需要去掉初始的6字节

          • local_variable_table_length u2 局部变量描述计数,表示LocalVariableTable的个数

          • local_variable_table[local_variable_table_ length] u10*local_variable_table_length 局部变量描述表集合 local_variable_ info

            • start_pc u2 开始字节码指令地址
            • length u2 字节码偏移量
            • name_index u2 局部变量名称索引,指向CONSTANT_Utf8_info中的非限定名
            • descriptor_index u2 局部变量字段描述符
            • index u2 方法执行时,局部变量在栈帧中局部变量表的位置,如果是double,long 它占用index,index+1
        • LocalVariableTypeTable 局部变量类型表,方法中使用了泛型变量,则会生成局部变量类型表,对泛型类型的局部变量,需要在LocalVariableTable Attribute和LocalVariableTypeTable Attribute中同时存在一项;而对非泛型类型的局部变量来说,只要在LocalVariableTable Attribute存在表项就可以

          如果方法中使用了泛型变量,则会生成 局部变量类型表;局部变量类型表的信息会覆盖掉 局部变量表的信息;JDK5之后才出现的 局部变量类型表,因为JDK5之前不支持泛型,为了兼容以前的老版本,不得不做了这个糟糕的设计;局部变量类型表在Hotspot中基本没有任何作用,仅用于作为Hotspot中的 局部变量表的 signature_cp_index字段赋值。

          • attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LocalVariableTypeTable”

          • attribute_length u4 属性长度,需要去掉初始的6字节

          • local_variable_type_table_length u2 表示LocalVariableTypeTable的个数

          • local_variable_type_table[local_variable_type_table_length]

            • start_pc u2 开始字节码指令地址
            • length u2 字节码偏移量
            • name_index u2 局部变量名称索引,指向CONSTANT_Utf8_info中的非限定名
            • signature_index u2 记录该项代表的局部变量的字段签名,指向CONSTANT_Utf8_info中
            • index u2 方法执行时,局部变量在栈帧中局部变量表的位置,如果是double,long 它占用index,index+1
        • StackMapTable stack_map_frame 栈图,为了提高JVM在类型检查的验证过程的效率,只用于Class文件加载时的校验

          • attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ StackMapTable”

          • attribute_length u4 属性长度,需要去掉初始的6字节

          • number_of_entries u2 表示entries表的成员数量

          • entries[number_of_entries] stack_map_frame

            • frame_type

              • same_frame

                • frame_type = SAME ;/ 0-63 /

                  • 该frame与前一个frame的局部变量区、操作数栈上对应位置的类型都完全一样,这个值也是隐含的 offset_delta,offset_delta=frame_type的值
              • same_locals_1_stack_item_frame

                • frame_type = SAME_LOCALS_1_STACK_ITEM; / 64-127 /

                  • 当前帧与上一帧有相同的局部变量,操作数栈中的变量数目为 1,隐式 offset_delta 为 frame_type - 64
                • verification_type_info stack[1];

              • same_locals_1_stack_item_frame_extended

                • frame_type u1= SAME_LOCALS_1_STACK_ITEM_EXTENDED;/* 64-127 */

                  • 与same_locals_1_stack_item_frame的区别就是offset_delta是明确给定的
                • offset_delta u2

                • verification_type_info stack[1]

              • chop_frame

                • frame_type = CHOP/ 248- 250 /

                  • 当前帧与上一帧具有相同的局部变量,知识不存在最后k个局部变量,并且操作数栈为空。k的值由公式251-frame_type给出,明确给出帧的offset_delta值
                • offset_delta u2

              • same_frame_extended

                • frame_type = SAME_FRAME_EXTENDED / 251/

                  • 局部变量信息和上一个帧相同,且操作数栈为空,与same_frame不同的是offset_delta明确给定的
                • offset_delta u2

              • append_frame

                • frame_type = APPEND ; / 252-254 /

                  • 当前帧比上一帧多了k个局部变量,且操作数栈为空,其中 k = frame_type -251
                • offset_delta u2

                • verification_type_info locals[frame_type - 251]

              • full_frame

                • frame_type = FULL_FRAME;/ 255 /

                  • 局部变量表和操作数栈做完整记录
                • offset_delta

                • number_of_locals

                • verification_type_info locals[number_of_locals]

                • u2 number_of_stack_items

                • verification_type_info stack[number_of_stack_items];

    • Exceptions 抛出异常的方法 Exception_ attribute_info

      • attribute_name_index u2 属性名称,指向名称为Exceptions 的常量池

      • attribute_length u4 属性长度

      • Number_of_exceptions u2 异常数量计数 ,表示有多少个异常名称索引

      • exceptions_index_table[Number_of_ exceptions] u2*Number_of_ exceptions 异常常量池索引

        • 每两个字节指向一个CONSTANT_Class_info类型 的常量池,全限定名称
    • RuntimeVisibleParameterAnnotations 该方法在运行时可见的修饰该方法参数的Annotation,Java程序可以通过反射机制获取这些Annotation中的值

      • attribute_name_index u2 属性名称,指向名称为RuntimeVisibleParameterAnnotations 的常量池

      • attribute_length u4 属性长度

      • num_parameters u1 记录该方法中的参数个数

      • parameter_annotations[num_parameters] annotation

        • type_index u2 指向CONSTANT_Utf8_info描述符

        • num_element_value_pairs

        • element_value_pairs[num_element_value_pairs] element_value_pairs

          • element_name_index,对应注解里字段的字段名称,指向CONSTANT_Utf8_info
          • value :加了注解的字段名为 record
    • RuntimeInvisibleParameterAnnotations 记录该方法在运行时不可见的修饰该方法参数的Annotation 结构与(RuntimeVisibleParameterAnnotations)相同

    • AnnotationDefault

      • attribute_name_index u2 属性名称,指向名称为AnnotationDefault 的常量池
      • attribute_length u4 属性长度
      • default_value 代码注解类型元素的默认值
    • MethodParameters

      • attribute_name_index u2 指向名称为“MethodParameters”的常量池

      • attribute_length u4 属性长度

      • parameters_count u1 参数的数量

      • parameters[parameters_count] parameter

        • name_index u2 值必须为0 或者指向常量池中的索引,如果为0 则parameters指向不带名称的形参,如果非0 则必须指向CONSTANT_Utf8_info 中的非限定名

attributes_count u2 属性表中的属性数量,记录原文件属性信息,一般一个类具有一个

attributes[attributes_count] attribute_info 官方定义为数组,实际上专属类描述的只有

  • SourceFile 记录源文件名称

    • attribute_name_index u2 属性名称索引,指向值为“ SourceFile”的常量池
    • attribute_length u4 属性长度 值必须为2
    • sourcefile_index 源文件名称索引,指向值CONSTANT_Utf8_info 中类地址的常量池
  • InnerClasses 内部类列表

    • attribute_name_index u2 属性名称索引,指向值为“ InnerClasses”的常量池
    • attribute_length 表示属性的长度,不包括前六个字节。
    • number_of_classes 表明classes数组冲的个数
    • classes[number_of_classes] 表示一个非包成员的类,都明确对应CONSTANT_Class_info中的一个类
  • EnclosingMethod 仅当一个类为局部类或者匿名类是才能拥有这个属性

    • attribute_name_index u2 属性名称索引,指向值为“ EnclosingMethod”的常量池
    • attribute_length u4 值必须为4
    • class_index u2 指向CONSTANT_Class_info中的
    • method_index u2 如果没有实现方法或构造函数的嵌套,则为0 ,否则指向CONSTANT_NameAndType_info的索引,
  • SourceDebugExtension

    • attribute_name_index u2 属性名称索引,指向值为“ SourceDebugExtension”的常量池
    • attribute_length u4 表示属性的长度,不包括前六个字节。
    • debug_extension[attribute_length] u1*attribute_length
  • BootstrapMethods 这个属性用于保存 invokedynamic 指令引用的引导方法限定符

    • attribute_name_index u2 属性名称索引,指向值为“ BootstrapMethods”的常量池

    • attribute_length u4 表示属性的长度,不包括前六个字节。

    • num_bootstrap_methods u2 数组中的引导方法限定符的数量

    • bootstrap_methods[num_bootstrap_methods]

      • bootstrap_method_ref u2

      • num_bootstrap_arguments u2

      • bootstrap_arguments[num_bootstrap_arguments] u2*num_bootstrap_arguments

        常量池在该索引处必须是下列结构之一:CONSTANT_String_info、CONSTANT_Class_info、CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_Float_info、CONSTANT_Double_info、CONSTANT_MethodHandle_info 或 CONSTANT_MethodType_info

字段描述符

方法:Object m(int i, double d, Thread t) {…}

方法描述符(IDLjava/lang/Thread;)Ljava/lang/Object;

Constant value attribute types

Field access

XMind: ZEN - Trial Version

关注公众号,每周都有新内容

获取脑图请回复公众号“class文件解析”获取PDF版本脑图,需要补充的知识点可以进行留言,逐步进行完善。

最后感谢大家的关注

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_31430665/article/details/106281119