是 由编译器按语句在源文件中出现的顺序,依次自动收集类中的 所有静态变量 的赋值动作 和 静态代码块中的语句,并进行合并。-->例子1
虚拟机会保证一个类的<clinit>()
方法在多线程环境中被正确地加锁、同步,如果多线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()
方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()
方法完毕。
例子1:演示类加载的初始化阶段
package li.reflection.classload_;
//演示类加载的初始化阶段
public class ClassLoad03 {
public static void main(String[] args) {
//分析:
/**
* 1.加载B类,并生成 B的Class对象
* 2.链接 :将num默认初始化为 0
* 3.初始化阶段:
* 3.1依次 自动收集类中的 所有静态变量的赋值动作 和 静态代码块中的语句,并合并
* 收集:
* clinit(){
* System.out.println("B的静态代码块被执行");
* num = 300;
* num = 100;
* }
* 合并:num =100;
*/
//直接使用类的静态属性也会导致类的加载
System.out.println(B.num);//100
}
}
class B {
static {
System.out.println("B的静态代码块被执行");
num = 300;
}
static int num = 100;
public B() {
System.out.println("B的构造器被执行");
}
}
例子2:
在例子1中的程序里创建一个B类对象,打上断点,debug源码:
可以看到在底层中,使用了对象锁synchronized (getClassLoadingLock(name))
:
也就是说,加载类的时候,是有类的同步控制机制。
正因为有这个机制,才能保证某个类在内存中,只有一份Class对象。