jvm之.class文件解读(下)(二)

简介: jvm之.class文件解读(下)(二)

属性表集合

方法表集合之后的属性表集合,指的是 class 文件所携带的辅助信息,比如该 class 文件的源文件的名称。以及任何带有 RetentionPolicy.CLASS 或者 RetentionPolicy.RUNTIME 的注解。这类信息通常被用于 Java 虚拟机的验证和运行,以及 Java 程序的调试,一般无须深入了解。

此外,字段表、方法表都可以有自己的属性表。用于描述某些场景专有的信息。

属性表集合的限制没有那么严格,不再要求各个属性表具有严格的顺序,并且只要不与已有的属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,但 Java 虚拟机运行时会忽略掉它不认识的属性。

属性计数器

attributes_count(属性计数器)

attributes_count 的值表示当前 class 文件属性表的成员个数。属性表中每一项都是一个 attribute_info 结构。

属性表

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 源码的行号与字节码指令的对应关系
LocalVariableTable Code 属性 方法的局部变量描述
StackMapTable Code 属性 JDK1.6 中新增的属性,供新的类型检查检验器和处理目标方法的局部变量和操作数有所需要的类是否匹配
Signature 类,方法表,字段表 用于支持泛型情况下的方法签名
SourceFile 类文件 记录源文件名称
SourceDebugExtension 类文件 用于存储额外的调试信息
Synthetic 类,方法表,字段表 标志方法或字段为编译器自动生成的
LocalVariableTypeTable 是哟很难过特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
RuntimeVisibleAnnotations 类,方法表,字段表 为动态注解提供支持
RuntimeInvisibleAnnotations 类,方法表,字段表 用于指明哪些注解是运行时不可见的
RuntimeVisibleParameterAnnotation 方法表 作用与 RuntimeVisibleAnnotations 属性类似,只不过作用对象或方法
RuntimeInvisibleParameterAnnotation 方法表 作用与 RuntimeInvisibleAnnotations 属性类似,只不过作用对象或方法
AnnotationDefault 方法表 用于记录注解类元素的默认值
BootstrapMethods 类文件 用于保存 invokeddynamic 指令引用的引导方法限定符

部分属性详解

① ConstantValue 属性

ConstantValue 属性表示一个常量字段的值。位于 field_info 结构的属性表中。

1. ConstantValue_attribute{
2.  u2 attribute_name_index;
3.  u4 attribute_length;
4.  u2 constantvalue_index;
5. //字段值在常量池中的索引,常量池在该索引处的项给出该属性表示的常量值。
6. (例如,值是1ong型的,在常量池中便是CONSTANT_Long)
7. }

② Deprecated 属性

Deprecated 属性是在 JDK1.1 为了支持注释中的关键词@deprecated 而引入的。

1. Deprecated_attribute{
2.  u2 attribute_name_index;
3.  u4 attribute_length;
4. }

③ 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_lenth 存储字节码指令
u2 exception_table_length 1 异常表长度
exception_info exception_table exception_length 异常表
u2 attributes_count 1 属性集合计数器
attribute_info attributes attributes_count 属性集合

可以看到:Code 属性表的前两项跟属性表是一致的,即 Code 属性表遵循属性表的结构,后面那些则是他自定义的结构。

④ InnerClasses 属性

为了方便说明特别定义一个表示类或接口的 Class 格式为 C。如果 C 的常量池中包含某个 CONSTANT_Class_info 成员,且这个成员所表示的类或接口不属于任何一个包,那么 C 的 ClassFile 结构的属性表中就必须含有对应的 InnerClasses 属性。InnerClasses 属性是在 JDK1.1 中为了支持内部类和内部接口而引入的,位于 ClassFile 结构的属性表。

⑤ LineNumberTable 属性

LineNumberTable 属性是可选变长属性,位于 Code 结构的属性表。

LineNumberTable 属性是用来描述 Java 源码行号与字节码行号之间的对应关系。这个属性可以用来在调试的时候定位代码执行的行数。

  • start_pc,即字节码行号;1ine_number,即 Java 源代码行号。

在 Code 属性的属性表中,LineNumberTable 属性可以按照任意顺序出现,此外,多个 LineNumberTable 属性可以共同表示一个行号在源文件中表示的内容,即 LineNumberTable 属性不需要与源文件的行一一对应。

1. // LineNumberTable属性表结构:
2. LineNumberTable_attribute{
3.     u2 attribute_name_index;
4.     u4 attribute_length;
5.     u2 line_number_table_length;
6.     {
7.         u2 start_pc;
8.         u2 line_number;
9.     } line_number_table[line_number_table_length];
10. }

⑥ LocalVariableTable 属性

LocalVariableTable 是可选变长属性,位于 Code 属性的属性表中。它被调试器用于确定方法在执行过程中局部变量的信息。在 Code 属性的属性表中,LocalVariableTable 属性可以按照任意顺序出现。Code 属性中的每个局部变量最多只能有一个 LocalVariableTable 属性。

  • start pc + length 表示这个变量在字节码中的生命周期起始和结束的偏移位置(this 生命周期从头 e 到结尾 10)
  • index 就是这个变量在局部变量表中的槽位(槽位可复用)
  • name 就是变量名
  • Descriptor 表示局部变量类型描述
1. // LocalVariableTable属性表结构:
2. LocalVariableTable_attribute{
3.     u2 attribute_name_index;
4.     u4 attribute_length;
5.     u2 local_variable_table_length;
6.     {
7.         u2 start_pc;
8.         u2 length;
9.         u2 name_index;
10.         u2 descriptor_index;
11.         u2 index;
12.     } local_variable_table[local_variable_table_length];
13. }

⑦ Signature 属性

Signature 属性是可选的定长属性,位于 ClassFile,field_info 或 method_info 结构的属性表中。在 Java 语言中,任何类、接口、初始化方法或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Types),则 Signature 属性会为它记录泛型签名信息。

⑧ SourceFile 属性

SourceFile 属性结构

类型 名称 数量 含义
u2 attribute_name_index 1 属性名索引
u4 attribute_length 1 属性长度
u2 sourcefile index 1 源码文件素引

可以看到,其长度总是固定的 8 个字节。

⑨ 其他属性

Java 虚拟机中预定义的属性有 20 多个

相关文章
|
7月前
|
安全 Java
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
45 0
|
2月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
36 3
|
2月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
59 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
5月前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
126 3
|
7月前
|
Java 索引
【JVM】字节码文件的组成部分
【JVM】字节码文件的组成部分
61 1
|
6月前
|
存储 Java 编译器
【搞定Jvm面试】 面试官:谈谈 JVM 类文件结构的认识
【搞定Jvm面试】 面试官:谈谈 JVM 类文件结构的认识
|
6月前
|
存储 XML 安全
JVM系列5-类文件结构
JVM系列5-类文件结构
38 0
|
7月前
|
存储 前端开发 Java
深入浅出JVM(四)之类文件结构
深入浅出JVM(四)之类文件结构
深入浅出JVM(四)之类文件结构
|
7月前
|
存储 XML 监控
JVM工作原理与实战(三):字节码文件的组成
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了字节码文件的基础信息、常量池、方法、字段、属性等内容。
114 6
|
7月前
|
存储 Java 索引
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,夯实底层基础 —— 吃透class字节码文件技术基底和实现原理(核心结构剖析)
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,夯实底层基础 —— 吃透class字节码文件技术基底和实现原理(核心结构剖析)
87 0