JVM 第一章 class文件的结构详解


访问标志分为类访问标志,字段访问标志,方法访问标志,内部类访问标志,一定要弄明白各自的作用范围,都是两字节,长的很像

以下两张图是类访问标志的标志位的具体含义




以下是字段的结构和字段的访问标志



以下是方法的结构和访问标志




以下是数据类型在虚拟机的表示方式


NO1. 魔数(magic)

所有的由Java编译器编译而成的class文件的前4个字节都是“0xCAFEBABE”  

它的作用在于:当JVM在尝试加载某个文件到内存中来的时候,会首先判断此class文件有没有JVM认为可以接受的“签名”,即JVM会首先读取文件的前4个字节,判断该4个字节是否是“0xCAFEBABE”,如果是,则JVM会认为可以将此文件当作class文件来加载并使用。

NO2.版本号(minor_version,major_version)

主版本号和次版本号在class文件中各占两个字节,副版本号占用第56两个字节,而主版本号则占用第78两个字节。JDK1.0的主版本号为45,以后的每个新主版本都会在原先版本的基础上加1。若现在使用的是JDK1.7编译出来的class文件,则相应的主版本号应该是51,对应的78个字节的十六进制的值应该是0x33

一个 JVM实例只能支持特定范围内的主版本号 (MiMj) 和0 至特定范围内 (0m) 的副版本号。假设一个Class 文件的格式版本号为V, 仅当Mi.0v Mj.m成立时,这个Class 文件才可以被此Java 虚拟机支持。不同版本的Java 虚拟机实现支持的版本号也不同,高版本号的Java 虚拟机实现可以支持低版本号的Class 文件,反之则不成立。

 

NO3.常量池计数器(constant_pool_count)

 常量池是class文件中非常重要的结构,它描述着整个class文件的字面量信息。 常量池是由一组constant_pool结构体数组组成的,而数组的大小则由常量池计数器指定。常量池计数器constant_pool_count 的值 =constant_pool表中的成员数+ 1。constant_pool表的索引值只有在大于 0 且小于constant_pool_count时才会被认为是有效的。

NO4.常量池数据区(constant_pool[contstant_pool_count-1])

常量池,constant_pool是一种表结构,它包含 Class 文件结构及其子结构中引用的所有字符串常量、 类或接口名、字段名和其它常量。 常量池中的每一项都具备相同的格式特征——第一个字节作为类型标记用于识别该项是哪种类型的常量,称为 “tag byte” 。常量池的索引范围是 1 至constant_pool_count−1

NO6.访问标志(access_flags)

NO7.类索引(this_class)

类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值。constant_pool表在这个索引处的项必须为CONSTANT_Class_info 类型常量,表示这个 Class 文件所定义的类或接口。

NO8.父类索引(super_class)

   父类索引,对于类来说,super_class 的值必须为 0 或者是对constant_pool 表中项目的一个有效索引值。如果它的值不为 0,那 constant_pool 表在这个索引处的项必须为CONSTANT_Class_info 类型常量,表示这个 Class 文件所定义的类的直接父类。当前类的直接父类,以及它所有间接父类的access_flag 中都不能带有ACC_FINAL 标记。对于接口来说,它的Class文件的super_class项的值必须是对constant_pool表中项目的一个有效索引值。constant_pool表在这个索引处的项必须为代表 java.lang.Object  CONSTANT_Class_info 类型常量 。如果 Class 文件的 super_class的值为 0,那这个Class文件只可能是定义的是java.lang.Object类,只有它是唯一没有父类的类。

NO9.接口计数器(interfaces_count)

接口计数器,interfaces_count的值表示当前类或接口的直接父接口数量。

NO10.接口信息数据区(interfaces[interfaces_count])

 接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为 interfaces_count。每个成员 interfaces[i]  必须为 CONSTANT_Class_info类型常量,其中 0 ≤ i <interfaces_count。在interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即interfaces[0]对应的是源代码中最左边的接口。

NO11.字段计数器(fields_count)

字段计数器,fields_count的值表示当前 Class 文件 fields[]数组的成员个数。 fields[]数组中每一项都是一个field_info结构的数据项,它用于表示该类或接口声明的类字段或者实例字段。

NO12.字段信息数据区(fields[fields_count])

字段表,fields[]数组中的每个成员都必须是一个fields_info结构的数据项,用于表示当前类或接口中某个字段的完整描述。 fields[]数组描述当前类或接口声明的所有字段,但不包括从父类或父接口继承的部分。

NO13.方法计数器(methods_count)

方法计数器, methods_count的值表示当前Class 文件 methods[]数组的成员个数。Methods[]数组中每一项都是一个 method_info 结构的数据项。

NO14.方法信息数据区(methods[methods_count])

方法表,methods[] 数组中的每个成员都必须是一个 method_info 结构的数据项,用于表示当前类或接口中某个方法的完整描述。如果某个method_info 结构的access_flags 项既没有设置 ACC_NATIVE 标志也没有设置ACC_ABSTRACT 标志,那么它所对应的方法体就应当可以被 Java 虚拟机直接从当前类加载,而不需要引用其它类。 method_info结构可以表示类和接口中定义的所有方法,包括实例方法、类方法、实例初始化方法方法和类或接口初始化方法方法methods[]数组只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法。

NO15.属性计数器(attributes_count)

 属性计数器,attributes_count的值表示当前 Class 文件attributes表的成员个数。attributes表中每一项都是一个attribute_info 结构的数据项

NO16.属性信息数据区(attributes[attributes_count])

    属性表,attributes 表的每个项的值必须是attribute_info结构。

    Java 7 规范里,Class文件结构中的attributes表的项包括下列定义的属性: InnerClasses  、 EnclosingMethod 、 Synthetic  、Signature、SourceFile,SourceDebugExtension 、Deprecated、RuntimeVisibleAnnotations 、RuntimeInvisibleAnnotations以及BootstrapMethods属性。

 对于支持 Class 文件格式版本号为 49.0 或更高的 Java 虚拟机实现,必须正确识别并读取attributes表中的SignatureRuntimeVisibleAnnotationsRuntimeInvisibleAnnotations属性。对于支持Class文件格式版本号为 51.0 或更高的 Java 虚拟机实现,必须正确识别并读取 attributes表中的BootstrapMethods属性。Java 7 规范 要求任一 Java 虚拟机实现可以自动忽略 Class 文件的 attributes表中的若干(甚至全部) 它不可识别的属性项。任何本规范未定义的属性不能影响Class文件的语义,只能提供附加的描述信息

好了,这个是class文件的宏观结构,里面还有很多具体的结构,下篇是介绍一下Attribute_info的结构,先放张图




猜你喜欢

转载自blog.csdn.net/qq_28816195/article/details/78750480