Class文件是一组以8个字节为基础单位的二进制字节流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据
这种伪结构中只有两种数据类型:“无符号数”与“表”
每个Class文件的头4个字节被称之为魔数,它的唯一作用是确定这个文件是否为一个能被虚拟机接收的Class文件,魔数的值为“0xCAFEBABE”,紧接着魔数的4个字节存储的是Class的版本号,第5、6个字节存储的是次版本号(Minor Version),第7、8个字节存储的是主版本号(Major Version)
紧接着主、次版本号之后就是常量池入口,常量池可以比喻为Class文件里的资源仓库,它是Class文件结构中与其他项目关联最多的数据,也是在Class文件中出现的第一个表类型数据项目
常量池中主要存放两大类常量:
Java代码在进行Javac编译的时候,不像是C或者C++那样有“连接”这一步骤,而是在虚拟机加载Class文件的时候进行动态连接,也就是说,在Class文件中不会保存各个方法、字段最终在内存中的布局信息,这些字段、方法的符号引用不经过虚拟机在运行期转换的话无法的到真正的内存入口地址,也就是无法直接被虚拟机使用的,当虚拟机做类加载的时候,将会在常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中
在常量池结束之后,紧接着2个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,具体的标志图如下:
| 标志名称 | 标志值 | 含义 |
| ACC_PUBLIC | 0x0001 | 是否为public类型 |
| ACC_FINAL | 0x0010 | 是否被声明为final,只有类可设置 |
| ACC_SUPER | 0x0020 | 是否允许使用invokespecial字节码指令的新语义,JDK1.0.2时候编译出来的类这个标志都为真 |
| ACC_INTERFACE | 0x0200 | 标识这是一个接口 |
| ACC_ABSTRACT | 0x0400 | 是否为abstract类型 |
| ACC_SYNTHETIC | 0x1000 | 标识这个类并非用户代码生成 |
| ACC_ANNOTATION | 0x2000 | 标识这是一个注解 |
| ACC_ENUM | 0x4000 | 标识这是一个枚举 |
| ACC_MODULE | 0x8000 | 标识这是一个模块 |
类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合,Class文件中由这三项数据来确定该类型的继承关系
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名(由于Java不允许多重继承,所以父类索引只有一个,除了Object之外,所有的java类都有父类,所有的父类索引都不为0)
字段表用于描述接口或者类中声明的变量,Java语言中的“字段”包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量,一个字段可以包含哪些信息呢?