第六章 类文件结构(读深入理解jvm虚拟机,随记)
6.2 无关性的基石
标题为什么是无关性基石呢。时至今日,商业机构和开源机构已经在java语言之外发展出一大批在java虚拟机上运行的语言。如Clojure,Groovy,Scala等。
java虚拟机不和包括java在内的任何语言绑定,它只与“Class文件”这种特定的二进制文件格式有所关联。 java程序(*.java)------>javac编译器------>字节码文件----->java虚拟机。
6.3 Class类文件的结构
如果想比较深入的了解虚拟机,那么这部分是不能不接触的。
注意⚠️:任何一个Class文件都对应着唯一一个类或接口的定义信息,但反过来说,类或接口并不一定都得定义在文件里(譬如类或接口也可以通过类加载器直接生成)。
Class文件是一组以8位字节为基础单位的二进制流,各个数据项严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符。
Class文件采用一种类似于C语言结构体的伪结构来存储数据。其只有两种数据类型:无符号数和表。
无符号数:属于基本数据类型。以u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数。无符号数可以用来描述:数字,索引引用,数量值或者按UTF-8编码构成字符串值。
表是由多个无符号数或者其他表构成的复合数据类型。都以“_info”结尾。 整个Class文件本质上就是一张表。
以上是Class文件的基本组成概述。后续继续详细介绍哪几个字节分别代表什么。
(1)魔数,class文件的版本(magic,minor_version,major_version)
每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否是一个可以被虚拟机接受的文件。
第5和第6字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。jdk1.1是(45~45.3),1.2是(45~46.3)以此类推,每次加一。
(2)常量池(constant_pool_count,constant_pool是表类型)
在主次版本号之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库。
常量池主要存放两大类常量:字面量(Literal)和符号引用。
字面量比较接近于java语言层面的常量概念,如文本字符串,声明为final的常量值等。
(3)访问标志位(access_flags)
常量池之后的两个字节代表 访问标志位(access_flags)。这个标志用于识别一些类或者接口层次的访问信息。包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。
(4)类索引,父类索引与接口索引集合
类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型数据的集合,Class文件中由这三项数据来确定这个类的继承关系。
(5)字段表集合
字段表(field_info)用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。
字段包括的信息有:字段的作用域(public,private,protected修饰符),是实例变量还是类变量(static修饰符),可变性(final),并发可见性(volatile修饰符,是否强制从主内存读写),可否被序列化(transient修饰符),字段数据类型,字段名称。
(6)方法表集合
(7)属性表集合
在Class文件,字段表,方法表都可以携带自己的属性表集合,以用于描述某些场景的专有信息。
6.4 字节码指令简介
(1)字节码与数据类型
在java虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息。
(2)加载和存储指令
加载和存储指令用于将数据在栈帧中的 局部变量表 和 操作数栈 之间来回传输。
(3)运算指令
(4)类型转换指令
(5)对象创建与访问指令
(6)操作数栈管理指令
(7)控制转移指令
(8)方法调用和返回指令
(9)异常处理指令
(10)同步指令