1. 程式人生 > >類例項化載入過程詳解

類例項化載入過程詳解

在看這篇部落格之前:

  • 想深入瞭解類的載入,從.class檔案到類被載入到虛擬機器並初始化可以檢視類的載入過程詳解

類的載入

什麼時候類載入:第一次需要使用類資訊時載入。
類載入的原則:延遲載入,能不載入就不載入。

這裡的類載入(類載入就是類的"初始化時機",不懂類的初始化時機可以檢視部落格:Java中 類的載入概述和載入時機)是指 沒有例項化前的載入,即初始化靜態變數 ,執行靜態變數語句,靜態初始化語句(靜態程式碼塊)。
把類從.class檔案載入到虛擬機器並且被初始化後,那麼這就已經做好了被例項化的準備。(例項化的兩個途徑,反射、new 這兩個途徑)

類被例項化的載入過程

這裡的例項化載入從.class檔案說起

例項化的載入順序

1.載入靜態成員/程式碼塊:

  • 先遞迴地載入父類的靜態成員/程式碼塊(Object的最先);再依次載入到本類的靜態成員。
  • 同一個類裡的靜態成員/程式碼塊,按寫程式碼的順序載入。
  • 如果其間呼叫靜態方法,則呼叫時會先執行靜態方法,再繼續載入。同一個類裡呼叫靜態方法時,可以不理會寫程式碼的順序。
  • 呼叫父類的靜態成員,可以像呼叫自己的一樣;但呼叫其子類的靜態成員,必須使用“子類名.成員名”來呼叫。

2.載入非靜態成員/普通程式碼塊,初始化構造方法:(例項塊在建立物件時才會被載入。而靜態成員在不建立物件時可以載入)

  • 先遞迴地載入父類的非靜態成員/程式碼塊(Object的最先),非靜態成員和程式碼塊按程式碼出現順序載入,並在載入完非靜態成員後初始化構造方法;再依次載入到本類的非靜態成員,並初始化構造方法,預設為無參構造,當然也可以指定父類初始化構造方法,和本類初始化構造方法。在子類構造方法中用super(引數列表);可以指定初始化父類構造方法,預設不寫super(引數列表)為初始化父類無參構造方法。
  • 同一個類裡的非靜態成員/普通程式碼塊,按寫程式碼的順序載入。同一個類裡呼叫方法時,可以不理會寫程式碼的順序。
  • 但呼叫屬性時,必須注意載入順序。一般編譯就會不通過。
  • 呼叫父類的非靜態成員(private 除外),也可以像呼叫自己的一樣。

總結:
靜態成員先初始化,只初始化一次,非靜態成員被例項化多次就初始化多次。所以靜態成員在記憶體中只有一份,而非靜態成員有多份。

一例子:

class Base{
     public static int a = 10;
     public int b = 20;
     static
     {
         System.out.println("Static Init Base "
+ a); //System.out.println("Null Init " + b); } public Base() { System.out.println("Init Base " + this.b); } } /** *一級子類和基類包含的內容一樣 **/ class SuperClass extends Base{ //靜態變數、靜態塊執行順序,按書寫先後順序 public static int a1 = getSuperStaticNumber(); public int b1 = getSuperInstanceNumber(); public SuperClass() { System.out.println("Init SuperClass" + this.b1); } static { System.out.println("Static Init SuperClass" + a1); } public static int getSuperStaticNumber() { System.out.println("Static member init"); return 100; } public int getSuperInstanceNumber() { System.out.println("Instance member init"); return 200; } } /** *二級子類為測試該程式碼的驅動類 */ public class Sub extends SuperClass{ public static int a2 = getStaticNumber(); public int b2 = getInstanceNumber(); public Sub() { System.out.println("Init SubClass " + this.b2); } public static int getStaticNumber() { System.out.println("Static member init Sub"); return 1000; } public int getInstanceNumber() { System.out.println("Instance member init Sub"); return 2000; } static { System.out.println("Static Init " + a2); } /** * 程式入口,main * * */ public static void main(String args[]) { new Sub(); } }

結果:

Static Init Base 10
Static member init
Static Init SuperClass100
Static member init Sub
Static Init 1000
Init Base 20
Instance member init
Init SuperClass200
Instance member init Sub
Init SubClass 2000