一文带你了解 Java 中 Class 类文件的结构(二)

109 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情

上一篇文章,我们简单看了下 Class 文件的基本结构,一文带你了解 Java 中 Class 类文件的结构(一) 今天,我们继续来看看 Class 类文件吧!

魔数与Class文件的版本

  • 每个 Class 文件的头 4 个字节被称为魔数 (Magic Number) ,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件。

  • 紧接着魔数的 4 个字节存储的是 Class 文件的版本号: 第 5 和第 6 个字节是次版本号(M inor Version),第 7 和第 8 个字节是主版本号(Major Version)

常量池

紧接着主、次版本号之后的是常量池入口,常量池可以比喻为 Class 文件里的资源仓库,它是 Class 文件结构中与其他项目关联最多的数据,通常也是占用Class文件空间最大的数据项目之一,另外,它还是在 Class 文件中第一个出现的表类型数据项目。

常量池中主要存放两大类常量

  • 字面量(Literal)
  • 符号引用(Symbolic References)。

字面量比较接近于 Java 语言层面的常量概念,如文本字符串、被声明为 final 的常量值等。

符号引用则属于编译原理方面的概念,主要包括下面几类常量:

  • 被模块导出或者开放的包(Package)
  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符
  • 方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
  • 动态调用点和动态常量 (Dynamically-Computed Call Site、Dynamically-Computed Constant)

访问标志

在常量池结束之后,紧接着的2个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息:

  • 这个 Class 是类还是接口
  • 是否定义为 public 类型
  • 是否定义为 abstract 类型
  • 如果是类的话,是否被声明为 final

除了上述的几个外还有很多,在此不一一列举

类索引、父类索引与接口索引集合

类索引和父类索引都是一个 u2 类型的数据,而接口索引集合是一组 u2 类型的数据的集合,Class 文件中由这三项数据来确定该类型的继承关系。

类索引用于确定这个类的全限定名。

父类索引用于确定这个类的父类的全限定名。由于Java语言不允许多重继承,所以父类索引只有一个,除了 java.lang.Object 之外,所有的Java类都有父类,因此除了 java.lang.Object 外,所有 Java 类的父类索引都不为0。

接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接口将按 implements 关键字(如果这个Class文件表示的是一个接口,则应当是 extends 关键字)后的接口顺序从左到右排列在接口索引集合中。

字段表集合

字段表用于描述接口或者类中声明的变量。Java 语言中的“字段”包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

方法表集合

Class 文件存储格式中对方法的描述与对字段的描述采用了几乎完全一致的方式,方法表的结构如同字段表一样,依 次包括访问标志、名称索引、描述符索引、属性表集合几项。

属性表

Class 文件、字段表、方法表都可以携带自己的属性表集合,以描述某些场景专有的信息。