JVM筆記 - 06類從上到下的初始化順序
目錄
說明:筆記內容來源於《北京聖思園教育 - 張龍老師 - 深入理解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