Class文件结构
1.Java代码可以跨平台运行的基础就是因为jvm的跨语言特性,无论哪种语言编写的程序,只要能编译成class文件,就能通过Jvm在各种平台上运行。实现这一特性的关键就是同意而强大的Class文件结构,它是异构语言与jvm之间的重要桥梁。(一次编译到处运行)
前端编译:将符合Java语法规范的Java代码转换位符合jvm规范的字节码文件。
Javac是一种能够将Java源码译为字节码的前端编译器
Javac编译器在将Java源码译为一个有效字节码文件的过程中经历了四个步骤,分别是词法解析,语法解析,语义解析以及生成字节码文件
字节码指令是由一个字节长度的、代表着某种特定含义的操作码以及跟随其后的零个至多个代表此操作所需参数的操作数所构成。虚拟机中许多指令并不包含操作数,只有一个操作码
Class 文件的结构严格按照上述结构体定义:
- 文件以一个 4 字节的魔数开头,紧跟着两个 2 字节的大小版本号
- 版本号之后是常量池,常量池的个数为 constant_pool_count,常量池的表项有 constant_pool_count - 1 个
- 常量池之后是类的访问修饰符、代表自身类引用、父类引用以及接口数量和实现的接口引用
- 接口之后有字段数量和描述,方法数量以及方法描述
- 最后存放着类文件的属性信息
目前,高版本的 JVM 可以执行由低版本编译器生成的 Class 文件,但是低版本的 JVM 不能执行由高版本编译器生成的 Class 文件,所以在实际的开发中,我们需要特别注意编译时使用的 JDK 版本与生产环境的 JDK 版本是否一致,如果不一致的话,会报出 UnsupportedClassVersionError
。
常量池**
常量池是class文件中内容最丰富的区域之一,随着Java虚拟机的不断发展,常量池的内容也不断丰富。同时,常量池对于Class文件中的字段和方法解析也有着至关重要的作用,可以说,常量池是整个class文件的基石。在版本号之后,紧跟着就是常量池的数量,以及若干个常量池表项。
TestClass 编译出来的 Class 文件中,constant_pool_count 为 0x10,也就是说这个 Class 文件中包含了 16 - 1 = 15
个常量项(常量池 0 为保留项,不存放实际内容)
在数量之后,就是常量池中各项的实际内容,不同类型的常量项的内容内容结构各不相同,但是一般都是以 “类型 - 长度 - 内容” 或者 “类型 - 内容” 的格式依次排列。在介绍我们的 TestClass 之前,我们先了解一下常量池项的类型都有哪些。