1. 程式人生 > 其它 >JVM筆記 - 06類從上到下的初始化順序

JVM筆記 - 06類從上到下的初始化順序

技術標籤:JVMjvm

目錄


說明:筆記內容來源於《北京聖思園教育 - 張龍老師 - 深入理解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