一、JVM探索之類的初始化順序
阿新 • • 發佈:2021-09-04
0、本文要點:
- 類的生命週期
- 類的初始化順序
- 總結
1、類的生命週期
首先談到類的初始化過程,就不得不復習一下類的生命週期
類的生命週期如下:
(1)載入
(2)連結:1️⃣驗證;2️⃣準備;3️⃣解析
(3)初始化
(4)使用
(5)解除安裝
2、類的初始化順序
(1)解釋
這裡我們所說的初始化順序,其實是一個class檔案裡各個部分的執行順序
(2)結論
前提:載入類方法(注意是載入)
第一步:
發生在連結-準備階段的初始化:
1)為類常量(static final)賦正式值
2)為類變數賦預設值(注意是系統預設值,不是程式碼給定的初始值)
注意:類變數、靜態程式碼塊的執行順序按程式碼順序從上到下,程式碼塊放在前面會先執行程式碼塊,但此時程式碼塊,可以對下面的類變數賦其他值,但是如果不能對類變數進行讀取操作,否則會報error: illegal forward reference(不合法的向前引用),這個道理也適用在物件變數和普通程式碼塊中間。
第2步:
1)發生在初始化階段的類變數賦初始值
執行靜態程式碼塊
第3步:
1)發生在使用階段,如果new了物件
1️⃣成員變數、普通程式碼塊初始化
2️⃣構造器
直接上程式碼:
public class Main {public static void main(String[] args) { System.out.println("Hello, World"); son.method();//靜態方法呼叫 執行1、2 //new son(); //物件呼叫 執行1、2、3、4 } } class son{ //2、靜態塊1 static{ i = 666; System.out.println("靜態程式碼塊1"); } //1、靜態變數 i\j,常量k賦預設值 //2、靜態變數 i\j賦值初值值static int i; static int j = 2; static final int k = 3; //2、靜態塊2 static{ System.out.println("靜態程式碼塊2"); j = 444; System.out.println("i = " + i + ",j = " + j + ",k = " + k); //i = 666,j = 444,k = 3 } //4、構造器 public son(){ a = 112; System.out.print("構造器" + ",j = " + j); System.out.print("構造器" + ",a = " + a); } //3、成員變數 int a = 111; //3、普通程式碼塊 { System.out.print("程式碼塊1"); b = 444; System.out.println("a = " + a ); //System.out.println("a = " + a + ",b" +b); //error: illegal forward reference 指b } int b = 333; public static void method(){ System.out.print("靜態方法"); i = 333; System.out.println("i = " + i + ",j = " + j + ",k = " + k); //i = 333,j = 444,k = 3 } }
3、對於有繼承關係的類初始化過程:
總結一句初始化來說就是:先父後子,先類(靜態)後物件,物件構方法在最後。
另外附一道面試題,幫助瞭解類載入
public class Test { public static void main(String[] args) { A a = A.getInstance();
/*解題原則:類只加載一次,因此類變數只初始化一次,
A:
先執行類的例項化,此時需要類的初始化
然後類變數 value2 執行一次賦值
B:
先執行類的初始化,其中value2已經賦值,然後在執行物件定義,此時不會再初始化value1\value2
*/ System.out.println("A value1:" + a.value1);//1 System.out.println("A value2:" + a.value2);//0 B b = B.getInstance(); System.out.println("B value1:" + b.value1);//1 System.out.println("B value2:" + b.value2);//1 } } class A{ private static A a = new A(); public static int value1; public static int value2 = 0; private A(){ value1++; value2++; } public static A getInstance(){ return a; } } class B{ public static int value1; public static int value2 = 0; private static B b = new B(); private B(){ value1++; value2++; } public static B getInstance(){ return b; } }