说明:笔记内容来源于《北京圣思园教育 - 张龙老师 - 深入理解JVM》视频课程。如有侵权,请联系删除。
1 类加载、连接、初始化的回顾
JVM笔记 - 01类加载器深入解析与阶段分解
JVM笔记 - 02类的加载、连接、始化过程详解
前面两篇内容,介绍了类的加载、连接、初始化,及主动使用类的场景。
2 类从上到下的初始化顺序
2.1 案例1
静态变量counter2的声明赋值,在构造方法前面
package com.test;
public class MyTest6 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("main=====counter1:" + singleton.counter1);
System.out.println("main=====counter2:" + singleton.counter2);
}
}
class Singleton {
public static int counter1;
//在构造函数的前面
public static int counter2 = 0;
private static Singleton singleton = new Singleton();
private Singleton() {
counter1++;
counter2++;
System.out.println("Singleton=====counter1:" + counter1);
System.out.println("Singleton=====counter2:" + counter2);
}
public static Singleton getInstance() {
return singleton;
}
}
执行结果为:
执行结果分析:
① main()方法中,"Singleton.getInstance()"调用了Singleton的静态方法,是对Singleton的主动使用
public class MyTest6 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("main=====counter1:" + singleton.counter1);
System.out.println("main=====counter2:" + singleton.counter2);
}
}
② 对Singleton的主动使用,会初始化Singleton。
在初始化Singleton之前,会先加载、连接Singleton
③ 连接Singleton,具体分为3个步骤:验证 -> 准备 -> 解析
④ 在连接的准备阶段,为会Singleton的静态变量分配内存,并将静态变量初始化为默认值。
准备阶段完成后,Singleton的静态变量的状态如下
//int的默认值为0
counter1 = 0;
counter2 = 0;
//引用类型的默认值为null
singleton = null;
⑤ 在初始化阶段,会为Singleton的静态变量赋予正确的初始值。
初始化的顺序,就是代码编写的顺序。
class Singleton {
public static int counter1;
//在构造函数的前面
public static int counter2 = 0;
private static Singleton singleton = new Singleton();
private Singleton() {
counter1++;
counter2++;
System.out.println("Singleton=====counter1:" + counter1);
System.out.println("Singleton=====counter2:" + counter2);
}
}
第1步,初始化counter1,因为代码中没有为counter1设置具体的数值,所以counter1的值仍然是准备阶段的默认值,即0
第2步,初始化counter2,因为代码中给counter2赋值为0,所以counter2的值是代码中设定的值,即0
第3步,初始化singleton,初始化singleton会执行构造函数。
在构造函数中,对counter1、counter2分别进行了自增1的操作,所以构造函数执行完成后,counter1值有0变为了1、counter2的值由0变为了1
⑥ 所以,main()方法中,打印counter1、counter2的值,得到的结果分别为 counter1 = 1,counter2 = 1
2.2 案例2
静态变量counter2的声明赋值,在构造方法后面
package com.test;
public class MyTest6 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println("main=====counter1:" + singleton.counter1);
System.out.println("main=====counter2:" + singleton.counter2);
}
}
class Singleton {
public static int counter1;
private static Singleton singleton = new Singleton();
private Singleton() {
counter1++;
counter2++;
System.out.println("Singleton=====counter1:" + counter1);
System.out.println("Singleton=====counter2:" + counter2);
}
//在构造函数的后面
public static int counter2 = 0;
public static Singleton getInstance() {
return singleton;
}
}
执行结果为:
执行结果分析:
①、②、③、④,案例1和案例2是相同的
⑤ 在初始化阶段,会为Singleton的静态变量赋予正确的初始值。
初始化的顺序,就是代码编写的顺序。
class Singleton {
public static int counter1;
private static Singleton singleton = new Singleton();
private Singleton() {
counter1++;
counter2++;
System.out.println("Singleton=====counter1:" + counter1);
System.out.println("Singleton=====counter2:" + counter2);
}
//在构造函数的后面
public static int counter2 = 0;
public static Singleton getInstance() {
return singleton;
}
}
第1步,初始化counter1,因为代码中没有为counter1设置具体的数值,所以counter1的值仍然是准备阶段的默认值,即0
第2步,初始化singleton,初始化singleton会执行构造函数。
在构造函数中,对counter1、counter2分别进行了自增1的操作,所以构造函数执行完成后,counter1值由0变为了1、counter2的值由0变为了1
第3步,初始化counter2,因为代码中给counter2赋值为0,所以counter2的值是代码中设定的值,即0。
因为counter2的位置在构造函数的后面,
所以在执行构造函数后,counter2 = 1,在counter2初始化完成后,counter2 = 0
⑥ 所以,main()方法中,打印counter1、counter2的值,得到的结果分别为 counter1 = 1,counter2 = 0