深入理解JVM之類加載器(二)

類的初始化詳解

       在深入理解JVM之類加載器(一)裏面我主要介紹了JVM中關於類的加載相關的一些知識,那在本文我將詳細介紹類的初始過程。我先編寫三個類,代碼如下:

public class MyTest {

    public static void main(String[] args) {
      
        System.out.printf(MyChild1.str);
//      System.out.printf(MyChild1.str2);
    }

}

class MyParent{
    public static String str="hello world";

    static {
        System.out.println("this is MyParent static");
    }
}
class MyChild extends MyParent{
    public static String str2="welcome!!";

    static {
        System.out.println("this is MyChild static");
    }
}

三個類的類名分別爲MyTest,MyParent , MyChild。其中MyChild是MyParent的子類,而MyTest擁有main方法,是一個啓動類。

首先我們在MyTest這個類中運行一下如下代碼:

System.out.printf(MyChild.str);

輸出結果爲:

this is MyParent static
hello world

 接着把剛纔的代碼改爲如下代碼再運行:

System.out.printf(MyChild.str2)

輸出結果爲:

this is MyParent static
this is MyChild static
welcome!!

 結果分析:

        第一次我們通過MyChild這個類調用它父類MyParent中的str這個靜態變量,輸出結果表明在執行 MyChild.str 時,執行了MyParent這個類中定義的靜態代碼塊,但是沒有執行MyChild中的靜態代碼塊。而在第二次運行時我們將str換成了MyChild這個類中定義的靜態變量str2,從輸出結果看出,此時代碼在運行時先執行了MyParent這個類中的靜態代碼塊,接着執行了MyChild中的靜態代碼塊,最後才輸出了str2的值。從以上分析我們得出結論:

  • 對於靜態字段來說,調用時只有直接定義了該字段的類纔會被初始化:在第一次運行時,我們訪問了MyParent中的靜態變量,即我們對MyParent這個類進行了主動使用,但是沒有訪問MyChild中的靜態變量,所以並沒有主動使用MyChild這個類,因此MyChild中的靜態代碼塊不會執行。總之,誰定義了靜態變量,使用這個靜態變量時就表示對誰的主動使用。
  • 當一個類在初始化時,要求其父類全部初始化完畢後,該類纔會被初始化:在第二次運行時,我們訪問了MyChild中的靜態變量,則主動使用了MyChild這個類,所以MyChild中的靜態代碼塊被執行了,但是卻先執行了MyParent中的靜態代碼塊,這是因爲MyChild是MyParent的子類,當初始化一個類的子類時父類也會主動使用。這一點我們可以通過配置虛擬機參數         -XX:+TraceClassLoding(用於追蹤類的加載信息並按順序打印出來)觀察得出,idea中配置方法如圖:

 具體加載信息由於篇幅太長我就不貼出來了,可自行配置並運行程序觀察。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章