Java类的生命周期-连接阶段
上篇讲述了类的加载阶段,通过类加载器读取字节码文件后在方法区与堆区生成对应的存放类信息的对象,本篇将讲解他的下一阶段-连接阶段
上篇说到类加载的五大阶段:
连接阶段又可以分为三个子阶段:验证-准备-解析 ,我们逐一讲解
1.验证
验证阶段的主要目的是检测java字节码文件是否遵守了《Java虚拟机规范》,此过程一般不需要开发者参与
主要有:
- 文件格式验证,文件开头是否为0XCAFEBABE,主次版本号是否满足当前Java虚拟机版本要求
- 元信息验证,例如类必须要有父类
- 验证程序执行指令的语义
- 符号引用验证,是否访问了其他类中的private字段
以主次版本号的验证为例子,观察JDK8虚拟机的源码,其判断逻辑规则如下:
return (major >= JAVA_MAIN_SUPPORTED_VERSION) &&
(major <= max_version) &&
((major != max_version) ||
(minor <= JAVA_MAIN_SUPPORTED_MINOR_VERSION));
major是主版本号,minor是副版本号,JAVA_MAIN_SUPPORTED_VERSION
是最低支持的版本号,为45,即JDK1.0,max_version
是最高版本号,即当前环境JDK版本号,如JDK8的52,所以字节码文件的主版本号要在45与当前版本号之间,JAVA_MAIN_SUPPORTED_MINOR_VERSION
是支持最高副版本号,JDK未使用为0,所以当主版本号等于max_version时,副版本号不能大于0
2.准备
准备阶段是为静态字段分配内存并设置初始值
设置初始值并不是直接将其设置为代码中赋予的值,例如:
public class Demo{
public static int i = 2;
}
在准备阶段呢,会为其开辟一份空间,并为其设置初始值为0,并不是2,而0就是默认值,赋值为2的操作会在下一阶段-初始化阶段执行,而每一种类型的静态字段都会在准备阶段赋予一个默认值:
数据类型 | 初始值 |
---|---|
int | 0 |
long | 0L |
short | 0 |
char | ‘\u0000’ |
byte | 0 |
boolean | false |
double | 0.0 |
引用数据类型 | null |
其目的是为了防止若代码中并未对其赋值,其内存中可能是之前残留的任意值
但是
如果静态字段的由final进行修饰,如:
public class Demo{
public static final int i = 2;
}
在准备阶段就会赋值为2,final修饰的基本数据类型会在准备阶段就为其赋值为代码中的值
3.解析
解析阶段就较为简单,就是将常量池中的符号引用替换为直接引用即内存地址引用
在字节码文件中对于常量池中的引用是符号引用,通过符号即可找到其引用的值,但是运行时这种寻找索引符号的方法速度非常慢
于是在解析阶段就会把符号索引全部替换为直接地址索引,直接通过地址就可以找到类的具体信息
这就是连接阶段的所有过程,看到这里如果对你有帮助请点一个关注,下一篇更新初始化阶段