概要
对于任何java程序而言,只要编译出来的class文件符合JVM虚拟机规范,那么就可以正常被执行。
那么为什么我们要了解class文件呢,不了解class文件我们业务代码不也写的好好的吗?我们学习class文件,一是当我们可以深入的了解我们所写的代码是怎样被编译,整个流程如果出错我们能够定位问题,例如当我们发现线上的业务逻辑执行地有问题的时候,我们在排查完主干上的代码,发现主干的代码没有任何异常。那么我们如果需要确认发布的线上机器的代码是否和主干上的确实一致。由于线上机器根本没有java文件供我们排查,只有class文件。这个时候我们只有通过javap来查看jvm为我们生成的代码,方便排查问题。第二个原因就是当我们发现有一段代码执行的流程和我们预测的不一样的时候,我们可以通过生成的class文件来查看jvm到底是执行我们这一段代码,从而可以深入的理解一些概念和原理。
如何查看字节码
当我们编写完java代码文件后会生成java文件,我们用javac可以将该java文件编译成后缀为class的文件,然后我们可以通过javap来查看里面的内容。
class文件的组成部分
根据JVM虚拟机规范的规定.Class文件格式采用一种类似于C语言结构体的存储数据,结构体中只有两种数据结构:无符号数和表。整个文件由下面的数据项构成。
名称 | 数量 | 说明 |
---|---|---|
magic | 1 | 魔数 |
minor_version | 1 | 次版本号 |
major_version | 1 | 主版本号 |
constant_pool_count | 1 | 常量池数量 |
constant_pool | constant_pool_count-1 | 各个常量的定义。为了后面的扩展。索引值为0的位置暂时空着,所以数量为常量池的容量大小- |
access_flags | 1 | 访问标识。代表的是一个类或者接口的访问信息,包括,这个class是接口还是类、是否定义为public、是否是抽象类等等 |
super_class | 1 | 父类 |
interfaces_count | 1 接口数量 | |
interfaces | interfaces_count | 接口索引 |
fields_counts | 1 | 变量的长度 |
fields | fileds_count | 变量 |
methods_count | 1 | |
methods | methods_count | |
attributes_count | 属性数量 | |
attributes | 属性 |
魔数
魔数是什么?其实就是一个文件的标识,因为文件后缀名可以任意改动,所以魔数的存在主要是为了安全性,对于非自己能够识别的文件,java可以直接拒绝执行,对于java来说同样的也会有一个四个字节的魔数。
次版本号和主版本号
主版本号和次版本号和我们日常的开发一样,在修改比较大的情况下,我们会修改主版本号,如果只是一些小的问题修复我们可能只会修改次版本号即可。JVM会根据版本号来决定是否执行。因为JVM是高版本兼容低版本,更高版本的class文件,由于无法判断是否有高级属性,所以一律不执行。
常量池
常量池可以认为是class文件中的仓库,常量池主要存放两类常量:字面量和符号引用。
字面量比较接近java语言层面的常量概念,如字符串、生命为final的常量值。符号引用主要包含了以下三类常量:
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
访问标识
访问标识包含两个字节,主要定义的是这个接口或者类的描述信息,是否是public、是否是接口、是否是抽象类等等。
父类索引
对于除了Object类外,别的类都有父类方法,父类字段指向一个类型为CONSTANT_Class_info的字段。通过它可以定位到父类是谁。
接口数量和接口索引
因为java是可以继承多个接口的,因此这里会定义接口的数量。而每个接口内容和上面的父类一样,同样指向接口信息类。
字段表集合
字段表中包含了接口或者类中声明的变量。不过不包含方法中的字段。因为作用域不一致。字段表包含字段的描述信息,例如访问标识、是否是类变量、字段名称等等。而对于访问标识、是否是类变量之类的信息,很适合用标志位来表示。而对于像名称、字段的类型之类的信息是动态变化的。所以字段表里的名称是索引,指向了常量池中的某个常量。而类型也是同样的
方法表
方法表用来描述java的方法,主要包括了方法的访问标识、方法名称的索引、方法描述符(方法的入参和返回值)等等。
方法表里面还有一个更重要的属性-用来描述方法的属性,例如方法会抛出哪些异常、code(方法体字节码)、异常表等等
属性表
和方法表一样,class文件也有一个属于自己的属性表,描述自己的一些基本信息,例如自己所属的java文件、内部类列表等等、