Java字节码文件(.class)结构略解3-属性表

属性表可选项

​ 属性表的一个集合作为.class文件是最后一项,其格式较为宽松,首先是各个属性表的顺序可以是任意的,其次是任何人都可以设计自己的属性表,只要不与现有的属性表冲突。

​ 字典时间,28种属性表:

属性名称 使用位置 含义
Code 方法表 Java代码编译成的字节码指令
ConstantValue 字段表 final修饰的基础数据类型的类变量(static)的值,虚拟机使用这个属性为变量赋值,使用常量池索引
Deprecated 类,方法表,字段表 被声明为deprecated的方法和字段,在代码中使用@deprecated注解,没有内容,长度为0
Exceptions 方法表 方法抛出的异常列表,列举出方法可能抛出的受查异常,使用多个常量池索引,索引项为CONSTANT_Class_info
EnclosingMethod 类文件 仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标示这个类所在的外围方法
InnerClasses 类文件 内部类列表,如果一个类定义了内部类,那么本类和其内部类都会有这个属性。保存了多个inner_class_info表
LineNumber Table Code属性 Java源码的行号与字节码指令的对应关系,使用多个line_number_table,由一个u2的start_pc指向字节码行号,以及一个u2的line_number指向Java源码行号
LocalVariableTable Code属性 描述栈帧中局部变量表与Java源码中定义的变量之间的关系,使用多个local_variable_info,在jdk5引入泛型后,使用LocalVariableTypeTable表示字段的特征签名
StackMapTable Code属性 JDK6中新增的属性,供新的类型检查验证器Type Checker检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配,包含多个栈映射帧
Signature 类, 方法表,字段表 JDK 5中新增的属性,用于支持范型情况下的方法签名。在Java语言中,任何类、接口、初始化方法或成员的泛型签名如果包含了类型变量(TypeVariables)或参数化类型(Parameterized Types),则Signature属性会为它记录泛型签名信息。由于Java的范型采用擦除法实现,为了避免类型信息被擦除后导致签名混乱,需要这个属性记录范型中的相关信息,包含一个常量池CONSTANT_Utf8_info项的索引,表示一个泛型签名信息
SourceFile 类文件 记录源文件名称,使用一个常量池索引
SourceDebugExtension 类文件 JDK 5中新增的属性,用于存储额外的调试信息。譬如在进行JSP 文件调试时,无法通过Java堆栈来定位到JSP文件的行号,JSR45提案为这些非Java语言编写,却需要编译成字节码并运行在Java虚拟机中的程序提供了一个进行调试的标准机制,使用该属性就可以用于存储这个标准所新加入的调试信息
Synthetic 类,放发表,字段表 标识方法或字段为编译器自动生成的,没有内容,长度为0
LocalVariableTypeTable JDK 5中新增的属性,它使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
RuntimeVisibleAnnotations 类,方法,字段表 JDK5中新增的属性,为动态注解提供支持。该属性用于指明哪些注解是运行时(实际上运行时就是进行反射调用)可见的,包含多个annotation表项,每一个都代表一个运行时可见的注解
RuntimelnvisibleAnnotations 类,方法,字段表 JDK5中新增的属性,与RuntimeVisibleAnnota-tions属性作用刚好相反,用于指明哪些注解是运行时不可见的
RuntimeVisibleParameterAn-notations 方法表 JDK5中新增的属性,作用与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法参数
RuntimelnvisibleParamcterAnnotations 方法表 JDK5中新增的属性,作用与 RuntimcInvisibleAnnotations属性类似,只不过作用对象为方法参数
AnnotationDefault 方法表 JDK5中新增的属性,用于记录注解类元素的默认值
BootstrapMethods 类文件 JDK7中新增的属性,用于保存invoke dynamic指令引用的引导方法限定符。如果某个类文件结构的常量池中曾经出现过CONSTANT_InvokeDynamic_info类型的常量,那么这个类文件的属性表中必须存在一个明确的BootstrapMethods属性,另外,即使CONSTANT_InvokeDynamic_info类型的常量在常量池中出现过多次,类文件的属性表中最多也只能有一个BootstrapMethods属性,包含多个bootstrap_method项,代表了一个引导方法。还包含了这个引导方法静态参数的序列(可能为空)
RuntimeVisibleTypeAnnotations 类,方法,字段表 JDK 8中新增的属性,为实现JSR308中新增的类型注解提供的支持,用于指明哪些类注解是运行时(实际上运行时就是进行反射调用)可见的
RuntimelnvisibleTypeAnnotations 类,方法,字段表 JDK 8中新增的属性,为实现JSR308中新增的类型注解提供的支持,与RuntimeVisibleTypeAnnotations属性作用刚好相反,用于指明哪些注解是运行时不可见的
MethodParameters 方法表 JDK 8中新增的属性,用于支持(编译时加上-parameters参数)将方法名称编译进Class文件中,并可运行时获取。此前要获取方法名称(典型的如IDE的代码提示)只能通过JavaDoc中得到。包含多个parameter
Module JDK 9中新增的属性,用于记录一个 Module的名称以及相关信息(requires ,exports.opens, uses ,provides), 模块化相关属性
ModulePackages JDK9中新增的属性,用于记录一个模块中所有被exports或者open的包,包含多个常量池CONSTANT_Package_info项索引
ModuleMainClass JDK 9中新增的属性、用于指定一个模块的主类,包含一个常量池CONSTANT_Class_info项索引
NestHost JDK 11中新增的属性,用于支持嵌套类(Java中的内部类)的反射和访问控制的API,一个内部类通过该属性得知自己的宿主类
NestMembers JDK 11中新增的属性,用于支持嵌套类(Java中的内部类)的反射和访问控制的API,一个宿主类通过该属性得知自己有哪些内部类

属性表大体结构

​ 对于一个合法的属性表,大体结构如下:

类型 名称 数量 意义
u2 attribute_name_index 1 指向一个常量表中的CONSTANT_Utf8_info类型,标识属性的名称
u4 attribute_length 1 标识属性表的长度,以字节为单位,不包括attribute_name_index和attribute_length所占用的6字节
u1 info attrubute_length 属性的值,对于每一个属性表来说,这一项的结构和意义是不同的

各个属性表

Code属性表结构

类型 名称 数量 意义
u2 attribute_name_index 1 指向一个常量表中的CONSTANT_Utf8_info类型,标识属性的名称
u4 attribute_length 1 标识属性项的长度
u2 max_stacks 1 操作数栈深度的最大值,虚拟机需要根据这个值分配栈帧中操作栈的深度
u4 max_locals 1 以槽(Slot)为单位代表局部变量(方法参数,显式异常处理的参数,方法体中的局部变量)所需的存储空间,注意这个空间是重用的,即一个变量因为超出作用域,其内存被释放后可用于存放下一个局部变量
u4 code_length 1 字节码指令的长度,以字节为单位
u1 code code_length 存放由Java代码翻译出的中间码,字节码,由于是8位的,总共可表达256条指令,目前以定义约200条
u2 exception_table_count 1 异常表的数量
exception exception_table exception_table_count 异常表项
u2 attributes_count 1 属性表的数量
attribute_info attributes attributes_count

异常项目结构(code中的异常表项)

类型 名称 数量 意义
u2 start_pc 1
u2 end_pc 1
u2 handler_pc 1
u2 catch_type 1 常量池索引,索引处的项为CONSTANT_Class_info

如果在start_pc和end_pc之间出现了catch_type类型的异常,那么转到handler_pc处执行,入宫catch_type的索引值为0,代表捕获任何异常

local_variable_info项目结构

类型 名称 数量 意义
u2 start_pc 1 生命周期开始的字节码偏移量
u2 length 1 作用范围的字节码偏移
u2 name_index 1 常量池索引,索引项为CONSTANT_Class_info,表示局部变量的名称
u2 descriptor_index 1 常量池索引,索引项为CONSTANT_Class_info,表示局部变量的描述符
u2 index 1 这个局部变量在栈帧中局部变量槽的起始位置

inner_class_info表结构

类型 名称 数量 内容
u2 inner_class_info_index 1 常量池CONSTANT_Class_info项索引,内部类的符号引用
u2 outer_class_info_index 1 常量池CONSTANT_Class_info项索引,外部类的符号引用
u2 inner_name_index 1 常量池CONSTANT_Utf8_info项索引,内部类类名
u2 inner_class_access_flags 1 内部类访问标志位

栈映射帧

每个栈映射帧都显式或者隐式的代表了一个字节码偏移量,用于表示执行到该字节码时局部变量表和操作数栈的验证类型。类型检查验证器会通过检查目标方法的局部变量和操作数栈所需要的类型来确定一段字节码指令是否符合逻辑约束.

bootstrap_method结构

类型 名称 数量 内容
u2 bootstrap_name_index 1 对常量池CONSTANT_MethodHandle_info项的索引
u2 num_bootstrap_arguments 1 bootstrap_argument的数量
u2 bootstrap_arguments 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其中一项的索引

parameter结构

类型 名称 数量 内容
u2 name_index 1 常量池中CONSTANT_Utf8_info项的索引
u2 access_flags 1 是否final修饰,编译器自动生成,隐式定义(比如this)

模块化相关属性

Module属性结构
类型 名称 数量 内容
u2 attribute_name_index 1 属性名
u4 attribute_length 1 属性字节长度
u2 module_name_index 1 常量池CONSTANT_Utf8_info项索引,模块名
u2 module_flags 1 模块是否开放,是否由编译器自动生成而非出现在源文件中,是否在源文件中隐式定义
u2 module_version_index 常量池CONSTANT_Utf8_info项索引,模块版本号
u2 requires_count
require requires
u2 exports_count 导出包的数量
export exports 每一个export项代表一个被模块所导出的包,
u2 opens_count
open opens
u2 uses_count
use uses_index
u2 provides_count
provide provides
exports项结构
类型 名称 数量 内容
u2 exports_index 1 常量池CONSTANT_Package_info项索引,代表该模块导出的包
u2 exports_flags 1 被导出包的状态指示器,是否由编译器自动生成而非源自源文件,是否该导出包是在源文件中隐式定义的
u2 exports_to_count 1 导出包的限定计时器,如果为0,则该导出包无限定,即完全开放
export exports_to_index exports_to_count 常量池中CONSTANT_Module_info项索引,代表能够访问导出包的模块

annotation结构

类型 名称 数量 内容
u2 type_index 1 以字段描述符形式表示一个注解,常量池CONSTANT_Utf8_info项索引
u2 num_element_value_pairs 1
element_value_pair element_value_pair num_element_value_pairs 作为一个键值对,代表注解的参数和值
上一篇:mysql数据库的 select查询


下一篇:Java 类文件结构