简介
本篇文章介绍类加载相关的内容
配套视频讲解:www.bilibili.com/video/BV173… (更新可能会迟到但不会缺席)
类加载是什么
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最 终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制 《深入理解Java虚拟机》
类加载阶段
加载
”加载“是类加载的第一个步骤主要进行以下几个操作
-
读取class文件到内存(就是读入一个流)
-
解析这个文件,并生成对应c++里的instaceKlass对象(instanceKlass存放在方法区)
-
生成instanceMirrorKlass存到堆
备注: 加载环节没有规定从哪里加载class文件,所以可以是从jar,war,数据库,动态生成。
验证
总而言之就是验证当前文件是否符合java虚拟机规范以及是否能被当前版本的jvm加载
准备
为静态变量赋零值
其实就是给被static 修饰的变量赋零值
零值: 不是代码中给变量赋的真实值,可以理解为初始值。
各个类型的零值是什么就不赘述了。
public class Test {
//这个阶段,不会给i赋值为10 而是0(int的零值)
public static int i = 10;
//不会给a赋零值,因为它是实例变量
public int a = 2;
}
解析
解析阶段是将符号引用解析成直接引用
符号引用,直接引用是什么呢 ?
我们现在都知道,java文件被jvm加载前要经过javac编译成class字节码
我们是不是可以认为class文件包含了所有java文件的代码信息了呢。(当然是),认可了这点后我们继续
准备一个类
public class Test {
HH h = new HH();
}
编译好后查看class文件(16进制)
看这一段
63 6f6d 2f68 616f 7a69 2f48 483b 0100 0a53 6f75 7263 6546 696c 6501 0007 4848
对照ascii转换成字符串刚好就是 com haozi HH,也就是说在class文件中 HH类还是用字符串表示的这个字符串我们可以看成是HH类的符号,这就是符号引用。直接引用就是将这个字符串换成HH类真正存放的内存地址
初始化
- 执行clinit
clinit是编译器产生的,内容是合并,所有的类变量,和static中的语句
细节
-
clinit是线程安全的,jvm执行时会加锁。
-
看个题目
public class Parent {
static int i = 1;
static {
System.out.println("parent");
}
}
*/
public class Son extends Parent {
static {
System.out.println("Son");
}
}
public class Test {
public static void main(String[] args) {
int i = Son.i;
}
}
执行结果为什么?
结果为 控制台打印 parent,因为访问的是son.i 而i是parent的类变量,所以就要执行parent的clinit方法初始化,进而执行static代码块。