Class 文件中的字段表、方法表与属性表

1. 前言

本节内容主要是介绍 Class 文件结构中的字段表、方法表与属性表。从本节标题的描述中,我们只看到了这 3 种表结构,但实际上本节会讲解 6 种结构,因为每一种表结构,都需要有计数器进行计数。本节主要知识点如下:

  • 字段表计数器和字段表的定义及意义,以及结构示意图,为本节重点内容之一;
  • 方法表计数器和方法表的定义及意义,以及结构示意图,为本节重点内容之一;
  • 属性表计数器和属性表的定义及意义,以及结构示意图,为本节次重点内容,由于JVM 对属性表没有特别规范的限制,此处了解其定义及结构即可。

本节所讲解的内容,是Class 文件结构的最后部分,学习完本节课程后,会对 Class 文件结构有一个整体的认识,并且每一部分的结构顺序与课程中讲解的顺序完全一样,把所有的示意图进行拼接,就能够形成一个完成的 Class 文件结构示意图。

2. 字段表计数器和字段表

上节课程抛出了问题,接口索引集合后边紧跟的结构是什么?这里我们来进行解答,后边紧跟的是字段表计数器,字段表计数器后边紧跟的是字段表。

定义:字段表计数器(fields_count)与字段表不可分割,这里我们对两部分结构一起讲解。

  • 字段表计数器(fields_count):记录字段表中字段的数量,为无符号数类型。
  • 字段表(fields):字段表(fields)用于描述接口或者类中声明的变量。字段(field)包括类级变量(即静态变量)以及实例变量(即:非静态变量),但不包括在方法内部声明的局部变量。字段表为表类型结构。

Tips:这里请学习者特别关注下字段表定义介绍中的最后两句话:“字段(field)包括类级变量(即静态变量)以及实例变量(即:非静态变量),但不包括在方法内部声明的局部变量。“ 简单的总结这句话的意思是字段表中存储的是全局标量,不存储局部变量。

字段表计数器无符号数结构示意图:与其他计数器一样,字段表计数器(fields_count)是一个无符号数结构类型的数据,u2 大小。

图片描述

字段表-表结构类型示意图:字段表是一个表结构的类型数据,回忆下我们接触到的第一个 Class 文件的表结构类型数据为常量池。这里我们来看下字段表的表结构示意图。

图片描述

前文提到过,字段(field)包括类级变量(即静态变量)以及实例变量(即:非静态变量),上图所示的一个 field_info 就代表了一个变量。为了表示一个变量,需要知道这个变量的修饰符,如 public,还需要知道这个变量的变量名称,因此一个 field_info 中存储了很多特征值,所有的特征值综合起来就完整的描述了一个变量。

3. 方法表计数器与方法表

字段表后边紧跟的是方法表计数器,方法表计数器后边紧跟的是方法表。

定义:方法表计数器(methods_count)与方法表不可分割,这里我们对两部分结构一起讲解。

  • 方法表计数器(methods_count):记录方法表中字段的数量,为无符号数类型。
  • 方法表(methods):存储了当前类或者当前接口中的 public 方法,protected 方法,default 方法,private 方法等。方法表为表结构类型。

Tips:Class文件是通过Java文件编译而来的,如果文件中有方法,就会将方法的信息存储到方法表,并通过方法表计数器进行方法的计数。

方法表计数器无符号数结构示意图:与其他计数器一样,方法表计数器(methods_count)是一个无符号数结构类型的数据,u2 大小。

图片描述

方法表-表结构类型示意图:方法表是一个表结构的类型数据,与前文所讲解的字段表结构一样。

图片描述

一个method_info中会存储很多方法的特征值,我们通过如下示例方法进行举例:

public String get(String name) {
	return "";
}

对于get 方法,method_info 中会存储如下信息:

  • 方法的修饰符 public:还记的我们上节所讲述的 access_flag 吗?access_flag 对应表中有一个 ACC_PUBLIC 就代表了 public 修饰符,他对应的值为 0x0001,此处的标记也需要使用到这个表。都是通用的哦;
  • 方法名称:get 方法;
  • 方法的参数:String name;
  • 方法的返回值类型: String 类型的返回值。

通过如上方法特征值的共同修饰,完成了一个 method_info 的存储,也就完成了一个方法的存储。

4.属性表计数器与属性表

方法表后边紧跟的是属性表计数器,属性表计数器后边紧跟的结构为属性表。至此,Class 文件的全部结构就讲解完了。回顾之前的知识,Class 文件结构是以魔数开头,以属性表结尾的。

定义:属性表计数器(attributes_count)与属性表不可分割,这里我们对两部分结构一起讲解。

  • 属性表计数器(attributes_count):记录属性表中属性的数量,为无符号数类型。
  • 属性表(attributes):属性表(attributes)与 Class 文件中其他的数据项目要求严格的顺序、长度和内容不同,属性表集合的限制稍微宽松一些,不再要求各个属性表具有严格的顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java 虚拟机运行时会忽略掉它不能识别的属性。

Tips:学习者对属性这一概念并不陌生了,这里不多加赘述,但是我们重点要关注下属性表的两大特点:一个是限制宽松,无顺序长度要求;一个是开发者可以自己向属性表中添加不重复的属性。言外之意是属性表作为 Class 文件的一个结构,是非常灵活的,且没有明确的长度大小规定。此部分知识我们稍作了解即可。

属性表计数器无符号数结构示意图:与其他计数器一样,属性表计数器(attributes_count)是一个无符号数结构类型的数据,u2 大小。

图片描述

属性表-表结构类型示意图:属性表也是一个表结构类型,与字段表、方法表结构类似,但是属性表没有固定的长度和顺序限制,此处我们了解下其结构即可。

图片描述

5. 小结

本节讲解了 Class 文件结构中最后的几种结构,分别是字段表计数器,字段表,方法表计数器,方法表,属性表计数器,属性表。其中字段表与方法表为本节重点内容,属性表部分视为次重点,仅做了解即可。

至此,我们的 Class 文件结构就讲解完了,我们回顾下 Class 文件的整体结构为:魔数->次版本号->主版本号->常量池计数器->常量池->类索引->父类索引->接口索引计数器->接口索引集合->字段表计数器->字段表->方法表计数器->方法表->属性表计数器->属性表。

学习者需要认真学习 Class 文件的数据结构,掌握整体结构以及细节知识点。