JVM 字节码文件
什么是字节码文件
计算机是无法直接识别Java程序的,我们编写的Java程序通过Java编译器编译成字节码文件,字节码文件任然不是计算机可以识别的二进制指令文件,需要通过Java虚拟机(JVM)将字节码文件转换成计算机可以识别的指令文件,然后才能运行。
在编译器中写的Java代码并不直接转换成计算机指令代码,而是通过JVM进行中间转换,解决了跨平台的问题,实现了一次编写,到处运行。
字节码文件结构
魔数
计算计读取一个文件时需要知道该文件的类型,仅靠文件名并不能确定文件类型。
所以往往在文件开头会有4个字节来标识文件类型,称之为“魔数”。
Java字节码文件的头4个字节是 0xCAFEBABE 代表Java字节码文件,JVM会识别文件的魔数,如果不是字节码文件,会被拒绝。
版本
字节码文件的魔数后面的4个字节用以确定版本。
前两个字节代表小版本,后两个字节代表大版本。
常量池
常量池作为字节码文件的资源库,主要存放变量和方法的属性、类型、名称等,包括下面三类常量:
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
常量池的索引从1开始,当不引用任何一个常量池项时,便可以将索引值设为0。
访问标志
在常量池之后的两个字节代表着这个字节码文件所属类的属性和访问类型。
包括该类是类还是接口,是public还是abstract或者是enum等。
类索引、父类索引、接口索引
类索引指向该类的全限定名。
父类索引指向父类的全限定名,由于Java的单继承,所有类都只有一个父类索引,除了所有类的祖先类Object
,只有Object类的父类索引为0。
接口索引用于确定该类实现了哪些接口。
字段表属性
字段表用于描述接口或类中的变量,不包括方法内的局部变量。
对于字段的名称、类型等会引用常量池中的常量来表示。
方法表属性
方法表用于描述方法的类型、作用域等。
对于方法的名称、类型等会引用常量池中的常量来表示。
属性表属性
用于描述某些场景下特殊的信息,比如字段表或方法表中特殊的属性等。
可以向属性表中写入自定义的属性,JVM运行时会忽略它不认识的属性。