1. 程式人生 > 其它 >一、JVM探索之類的初始化順序

一、JVM探索之類的初始化順序

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; } }