class类文件结构
引言
JVM最重要的特点之一就是平台无关性,做到平台无关性的基石就是class文件。任何一种语言(java、groovy、ruby)等,通过他们特殊的编译器,生成了可以在JVM中运行的class文件。
class文件是以8位字节为基础单位的二进制流。没有分隔符。
基本数据类型
class文件中只有两种基本数据类型:无符号数和表
无符号数
无符号数可以用来描述数字、索引引言、数值量、UTF-8字符串值等。 分为:u1,u2,u4,u8 表示由1,2,4,8个字节组成的无符号数。
表
表常以【_info】结尾,用于表示符合组合关系的i数据结构。
class文件组成
- 魔数(前四个字节,包含文件类型、class版本号、次版本号、主版本号)
- 常量池(大小不固定 由以下三部分组成)
- u2无符号数,表示常量池大小
- 字面量(字符串、声明为final的常量值等)
- 符号引言(类&接口的全限定名、字段的名称&描述符、方法的名称&描述符)
- 访问标志(识别该class是类还是接口,public or abstract or final等)
- 类索引(u2无符号数,表示类的全限定名)
- 父类索引(u2无符号数,表示父类的全限定名)
- 接口索引(容量大小+一组u2的无符号数, 表示接口们的全限定名)
- 字段表(除局部变量外的类变量,包含字段访问符、字段数据类型、字段名称)
- 方法表(描述方法,类似字段表,方法描述先返回值再属性)
- 属性表
为什么Java语言无法根据返回值的不同对方法重载?
因为Java方法表中,识别重载方法的依据是他们的特征签名不一致,特征签名指一个方法中的参数们在常量池中的引用,不包含返回值。
字节码指令
字节码由操作码+操作数组成
JVM中操作码长度为1字节,对于char、boolean等不满一字节的运算会转化成int类型字节码处理。
在class文件中执行的一些操作就是字节码指令,下面列出常见指令
- 加载&存储指令
- 用于堆栈中的局部变量与操作数栈交互的指令
- 加载局部变量 -> 操作数栈:iload、fload等
- 将数值从操作数栈存储至 -> 局部变量表:istore、fstore等
- 加载常量 -> 操作数占 bipush
- 运算指令
- 在操作数栈上的特定运算
- 加法 iadd
- 减法 isub
- 乘法 imul
- 除法 idiv
- ….
- 类型转化指令
- 常用于显示转化
- 也用于上面提到的 boolean等字节码被转成int码,再转回去(字节码与数据类型无法一一对应)
- 对象创建与访问指令
- 创建对象 new \ newarray
- 访问类字段 getfield \ getstatic
- 类型检查 instanceof checkcast
- 操作数栈管理指令
- pop pop2(取两个栈顶元素)
- dup 复制
- swap
- 控制转移指令
- 修改PC寄存器的值(ifeq、goto等)
- 方法调用&返回
- invoke & ireturn
- 异常处理指令(athrow)
- 同步指令 (synchornized)
- 分为方法级同步 和 方法内部一段指令同步
- 两种同步方式通过
管程实现 - 方法级同步是隐式的,时机是方法调用和返回操作数栈时,识别标志(ACC_SYNCHRONIZED)
- 方法内部一段指令同步通过synchronized语句来表示代码块,对应的指令为monitorreturn、monitorexit