attributes [] (属性表)
属性表的每个项的值必须是attribute_info结构。属性表的结构比较灵活,各种不同的属性只需要满足以下结构即可。
属性的通用格式
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | attribute_name_index | 1 | 属性名索引 |
u4 | attribute_length | 1 | 属性长度 |
u1 | info | attribute_length | 属性表 |
即只需说明属性的名称以及占用位数的长度即可,属性表具体的结构可以去自定义。
属性类型
属性表实际上可以有很多类型,上面看到的Code属性只是其中一种,Java8里面定义了23种属性。
下面这些是虚拟机中预定义的属性:
属性名称 | 使用位置 | 含义 |
---|---|---|
Code | 方法表 | Java代码编译成的字节码定义 |
ConstantValue | 字段表 | final关键字定义的常量池 |
Deprecated | 类,方法,字段表 | 被声明为deprecated的方法和字段 |
Exceptions | 方法表 | 方法抛出的异常 |
EnclosingMethod | 类文件 | 仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法 |
InnerClass | 类文件 | 内部类列表 |
LineNumberTable | Code属性 | Java源码的行号于字节码指令的对应关系 |
LocalVaribaleTable | Code属性 | 方法的局部变量描述 |
StackMapTable | Code属性 | JDK1.6中新增的属性,供新的类型检查检验器检查和处理目标方法的局部变量和操作数有所需要的类是否匹配 |
Signature | 类,方法表,字段表 | 用于支持泛型情况下的方法签名 |
SourceFile | 类文件 | 记录源文件名称 |
SourceDebugException | 类文件 | 用于存储额外的调试信息 |
Synthetic | 类,方法表,字段表 | 标志方法或字段为编译器自动生成的 |
LocalVaribaleTypeTable | 类 | 使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加 |
RuntimeVisibleAnnotations | 类,方法表,字段表 | 为动态注解提供支持 |
RuntimeInvisibleAnnotations | 表,方法表,字段表 | 用于指明哪些注解是运行时不可见的 |
RuntimeVisibleParameterAnnotation | 方法表 | 作用与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法 |
RuntimeInvisibleParameterAnnotation | 方法表 | 作用与RuntimeInvisibleAnnotations属性类似,作用对象哪个为方法参数 |
AnnotationDefault | 方法表 | 用于记录注解类元素的默认值 |
BootsrapMethods | 类文件 | 用于保存invokeddynamic指令引用的引导方式限定符 |
部分属性详解
- Code属性
Code属性就是存放方法体里面的代码。但是,并非所有方法表都有Code属性。像接口或者抽象方法,他们没有具体的方法体,因此也就不会有Code属性了。
Code属性表的结构,如下图:
类型 | 名称 | 数量 | 含义 |
---|---|---|---|
u2 | attribute_name_index | 1 | 属性名索引 |
u4 | attribute_length | 1 | 属性长度 |
u2 | max_stack | 1 | 操作数栈深度的最大值 |
u2 | max_locals | 1 | 局部变量表所需的存续空间 |
u4 | code_length | 1 | 字节码指令的长度 |
u1 | code | code_length | 存储字节码指令 |
u2 | exception_table_length | 1 | 异常表长度 |
exception_info | exception_table | exception_length | 异常表 |
u2 | attributes_count | 1 | 属性集合计数器 |
attribute_info | attributes | attributes_count | 属性集合 |
可以看到:Code属性表的前两项跟属性表是一致的,即Code属性表遵循属性表的结构,后面那些则是他自定义的结构。
-
LineNumberTable属性
LineNumberTable 属性是可选变长属性,位于 Code 结构的属性表。
LineNumberTable属性是用来描述Java源码行号与字节码行号之间的对应关系。
这个属性可以用来在调试的时候定位代码执行的行数。-
start_pc,即字节码行号;line_number,即Java源代码行号。
在Code属性的属性表中,LineNumberTable属性可以按照任意顺序出现,此外,多个LineNumberTable属性可以共同表示一个行号在源文件中表示的内容,即LineNumberTable属性不需要与源文件的行一一对应。
LineNumberTable属性表结构:
-
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{
u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length]
}
- LocalVariableTable属性
LocalVariableTable 是可选变长属性,位于Code属性的属性表中。它被调试器用于确定方法在执行过程中局部变量的信息。
在Code属性的属性表中,LocalVariableTable属性可以按照任意顺序出现。Code 属性中的每个局部变量最多只能由一个LocalVariableTable属性。start pc + length 表示这个变量在字节码中的生命周期起始和结束的偏移位置(this生命周期从头0到结尾10)
index就是这个变量在局部变量表中的槽位(槽位可复用)
name就是变量名称
-
Descriptor表示局部变量类型描述
LocalVariableTable属性表结构:
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_variable_table_length;
{
u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
} local_variable_table[line_variable_table_length];
}
梦想很模糊,去追,它会渐变清晰。青春励志,奋斗下去别放弃。
网友评论