一、加载
二、链接
验证:验证类是否符合JVM规范,安全性检查
例如:如果修改了类的class文件的魔数信息,就会验证不通过,报错
准备: 为static变量分配空间,设置默认值
- static变量在JDK7 之前是存在instanceKlass 的末尾,JDK7开始之后,就存在java- mirror末尾
- static 变量 的 分配空间和赋值是两个步骤, 分配空间是在 链接 的准备阶段, 赋值是在后面的初始化阶段
- static变量 如果是final修饰的基本数据类型跟字符串常量,在编译阶段值就确定了,所以在准备阶段就赋值了
- 但是如果final修饰的是引用数据类型,那么也是在初始化阶段才会被赋值
解析: 将常量池中的符号引用 解析 为直接引用
加载class类到方法区,然后下面的链接和初始化都是为了初始化方法区class类的成员变量,链接是初始化常量池字符引用为真正引用,初始化是给_mirror赋值
- 如果通过类加载器加载类C,这时候类C只会被加载,不会被解析初始化,
那么这时候D也不会被加载、解析初始化
这时候D只是C中的一个未解析的符号引用,虚拟机是不知道他是什么东西的,也不知道他的内存地址。
- 如果创建了类C的实例对象,那么这时候就会加载 、 链接、 初始化
- 这也就会将D也加载、链接、初始化
- 这时候就将D的符号引用 解析成了 直接引用,这时候就知道他是什么了,类,方法具体在什么位置。
三、初始化
就是执行类的构造方法的阶段,也就是执行<cinit>()V 方法的阶段,虚拟机会保证类的【构造方法】的线程安全
发生的时机(概括的说,类初始化是【懒惰的】) :
不会导致类初始化情况
练习:(懒惰式单例模式)
- 如果调用静态方法test() , 那么他是不会加载LazyHolder,因为根本没用到
- 如果调用静态方法getInstance(), 那么就会进行加载,从而实现了懒加载,用到时候加载
- 线程安全的,因为静态内部类的静态变量跟静态代码块是由类加载器保证线程安全的