(五)Class类文件结构

Class类文件结构

(五)Class类文件结构_第1张图片

注意一下讲解都是基于该Class文件结构;

任何一个Class文件都对应着一个类或者接口的定义信息;
Class文件是一组以8位字节为基础单位的二进制流;

Class文件存储结构:只有两种数据类型:无符号数和表

无符号数

无符号数属于基本数据类型:以u1、u2、u4、u8来代表一个字节、两个字节、三个字节、四个字节的无符号数

作用:可以用来描述数量值、索引引用、数字或者按照utf-8编码构成的字符串值;

是由无符号数和其他表作为数据项构成的复合数据类型,所有表都一般以"_info"结尾;

Class文件格式

(五)Class类文件结构_第2张图片

1.魔数-Magic

Class文件的头四个字节成为魔数;

作用:确定这个Class文件能否被虚拟机接受
##2.Class文件版本号 ##
对应上图第二、三数据项:minor_version(次版本号) 、Major_Version(主版本号)
java版本号是从45开始的

3、常量池-Constant_pool

他是Class文件结构中和其他项目关联项目最多的数据类型,也是占用Class文件空间最大的数据项目之一;

由于常量池中的常量数量是不固定的,为此常量池入口需要放置一个u2数据类型的数据,代表常量池容量计数值(Constant_pool_count)

注意:常量池容量计数从1开始的比如:常量池计数对应的u2类型数据是0x0016对应的十进制为22,表示常量池中有22个常量(索引范围就是1-21);

常量池中主要用于存放两大类常量:字面量(比如文本字符串、声明为final的常量等)和符号引用

符号引用包含以下三类常量:

  1. 类和接口的全限定名
  2. 字段的名称和描述符
  3. 方法的名称和描述符

常量池中每一项常量都是一个表;到JDK1.7共有14中表类型
(五)Class类文件结构_第3张图片

这14中表结构都有一个共同点:表开始的第一位是一个u1类型的标志位(取值对应上图的标志列),用于判断该常量时哪种表类型;对应Class文件的结构图中(偏移量地址:0x0000000A)的0x07,即说明该常量时CONSTANT_Class_info类型的表,该常量是类或者接口符号引用;

以CONSTANT_Class_info表结构为例:

u1是上面我们说的标志位,name_index是一个索引值指向常量池中一个CONSTANT_String_info类型常量,此常量代表了一个这个类或者接口全限定名;即偏移地址(0x0000000B)为0x0002,换算成十进制2(表示指向常量中第2个常量),该常量的标志位即偏移地址:0X0000000D)为0x01,即标志为1,通过查看上面的表类型图说明该常量是CONSTANT_Uft8_info类型的常量;

5、访问标志

常量池结束后紧接着两个字节表示访问标志,用于标志类或者接口层次的访问信息包括:

  1. 这个Class是接口还是类
  2. 是否被定义为public类型
  3. 是否被定义为abstract类型
  4. 如果是类,是否被声明为final

具体标志位:

![](http://linleslie.test.upcdn.net/%E6%B7%B1%E5%85%A5java%E8%99%9A%E6%8B%9F%E6%9C%BA/16%E3%80%81%E8%AE%BF%E9%97%AE%E6%A0%87%E5%BF%97%E4%BD%8D.

由于是两个字节,所有有16个标志位,当前只定义了8个标志位,未使用的标志位为0;

6、类索引、父类索引、接口索引

由这三项数据用于确定类的继承关系;

类索引:确定这个类的全限定名;

父类索引:这个类的父类全限定名,java不允许多继承,索引除了Object没有父类,其父类索引为0 外,其他任何类都有父类索引

接口索引:用于描述这个类实现接口的全限定名

this_Class、Super_Class时一个u2类型的数据,而interface_Class是一组u2类型数据集合;

查找类、父类全限定名:

  1. 通过类索引、父类索引的u2类型索引值,它们各自指向一个CONSTANT_Class_info的类描述符常量,通过该常量中的索引值可以找到CONSTANT_Utf8_info类型常量中的全限定类名字符串

查找实现接口

入口第一项,u2类型的连个字节表示实现的接口数量,后面的这N个数量的u2类型索引值,它们各自指向一个CONSTANT_Class_info的类描述符常量,通过该常量中的索引值可以找到CONSTANT_Utf8_info类型常量中的全限定接口名字符串

7、字段表集合

字段表集合前是一个u2类型的数据:表示有多少个字段表,紧接着就是具体的所有字段表;

字段表:用于描述接口和类中定义的成员变量,成员变量包括的信息:

  1. 作用域即访问修饰符(private、public等)
  2. 是实例变量还是那个静态成员变量
  3. 可变形(final)
  4. 并发可见性(volatile修饰,是否强制从主内存读写)
  5. 可否序列化(transient修饰符)
  6. 数据类型(基本类型、引用类型)
  7. 成员变量名称

这些通过一个u2类型的访问标志来实现(和类访问标志位大同小异);

(五)Class类文件结构_第4张图片

字段表结构:

(五)Class类文件结构_第5张图片

紧接着是两项索引值:name_index、descriptor_index都是对常量池的引用,表示字段名、字段描述符;

关于成员变量简单名称、类全限定名以及成员变量、方法描述讲解:

简单名:即变量名、方法名

类全限定名:把类全名如:java.lang.Object中的“.”换成了“/”java/lang/Object

成员变量描述符:描述变量类型
方法描述符:方法的参数列表(包括数量、类型、顺序)和返回值

基本数据类型(boolean、long除外)和无返回值的void类型用其首字母大写表示

对象类型使用大写L加类的全限定名

:如

(五)Class类文件结构_第6张图片

数组的每一维度使用一个[表示如:

			String[][]----->[[Ljava/lang/String

方法描述符如:

	public char test(String[][] s,int b,long c,Int d){}


	对应描述符为:([[Ljava/lang/StringIJI)C 

字段表集合不会列出从超类或者父接口中继承而来的成员变量

8、方法表集合

和字段表结构大同小异:

(五)Class类文件结构_第7张图片

有点区别的就是访问标志:

(五)Class类文件结构_第8张图片

方法中的代码经编译器编译成字节码指令后存放在属性表中的名为"Code"的属性里;

注意:父类的方法在子类中没有被重写,不会出现子类方法表集合中

9、属性表集合

48)]

有点区别的就是访问标志:

[外链图片转存中…(img-kzt10Njt-1594971298850)]

方法中的代码经编译器编译成字节码指令后存放在属性表中的名为"Code"的属性里;

注意:父类的方法在子类中没有被重写,不会出现子类方法表集合中

9、属性表集合

你可能感兴趣的:(Java虚拟机)