概述
class 文件也称字节码文件,他是JVM执行的具体文件格式,他并不是JAVA所特有的,任何语言只要他能编译成字节码文件他就能在JVM上执行,同时也就具备了跨平台的特性。今天我们就来聊一下 Class 文件的结构。
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符。Class文件值存储数据只有两种数据类型:无符号数和表。
- 无符号数: u1(表示1字节无符号数)、u2(表示2字节)、u4、u8
- 表: 多个无符号数或其他表组成的复合类型(_info结尾)
Class 文件本质上就是一个表,他长下边这个样子,由于他实际的存储就是一堆0和1的二进制流,所以说下边所列出的表项都是有具体意义、具体大小、具体顺序的,先前就规定好了不允许改变(改了就不知道谁是谁了),我们要学的就是每个字段的含义。
详细介绍
生成字节码
- 我们先来写个java程序,然后看他的字节码文件,以便于我们逐字节讲解。
public class TestByteCode{
private int m;
public int inc(){
return m+1;
}
}
- 使用Idea的插件查看字节码
1. 魔数(Magic Number)
我们会发现他是第一个字段(idea中没有显示),大小为4个字节,也就是对应class文件字节流的前32个二进制位。他的作用是标识这个文件是class文件,所以他是固定的,对应的十六进制表示为0xCAFEBABE(咖啡北鼻,有没有联想到java的图案,是不是感觉都联系起来了!)
2. 版本号
此部分占用4个字节,首先是次版本号(两个字节),之后是主版本号(两个字节), 如图分别是0和52,"[]" 内的是此插件对该字节码的翻译,由此可看出我的jdk版本为1.8
3. 常量池
接下来首先是常量池计数,这是一个u2类型的数据,代表了常量池容量的计数。如图,常量池计数为22,就代表常量池包含了21个数据(索引为1-21,第0号索引空了出来)。
常量池中存放的主要有两大类常量:字面量和符号引用。字面量主要是指java里的常量(final 修饰的变量/文本字符串);符号引用主要是:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。常量池的每一项都是一个表,如图所示。
表开始的第一位是一个u1类型的标志位,来表示当前常量是哪个类型。如下图的 Class_info 表,他的第二项是类名索引,指向的是一个CONSTANT_Utf8_info 类型的表项
我们继续点到常量池的第20个表项,我们会发现类名是“TestByteCode”
CONSTANT_Utf8_info 表项的结构如下:
以上我们分析了Class_info表项,常量池中所有的表项均可以通过以上的方式进行分析。接下来给出所有表项的结构信息,方便大家分析:
好了,常量池是类文件中最大最繁琐的一段空间了,回顾一下,我们讲垃圾回收机制的时候是不是也说从常量池的对象引用开始遍历,所以这块东西还是蛮多的,大家先消化一下吧,下次我们接着介绍字节码文件的其他内容。