虛擬機器在載入JAVA類的時候,按照一定的順序進行載入,瞭解虛擬機器的載入順序,可以有助於我們更好的去解決問題,下面我們來通過實際的現象來觀察虛擬機器是如何載入並初始化類的。
為了可以更好的查看初始化過程,我們先來建立一個Log類,用來輸出初始化資訊:
package com.jianggujin.loadeorder;public class Log{ public Log(String msg) { System.err.println(msg); }}
在Log類的對象初始化的時候,直接輸出相關資訊。
接下來,我們分別建立Parent和Child類:
Parent.java
package com.jianggujin.loadeorder;public class Parent{ Log log1 = new Log("父類普通屬性"); static Log log2 = new Log("父類靜態屬性"); static { System.err.println("父類靜態代碼塊"); } public Parent() { System.err.println("父類構造方法"); }}
Child.java
package com.jianggujin.loadeorder;public class Child extends Parent{ Log log1 = new Log("子類普通屬性"); static { System.err.println("子類靜態代碼塊"); } static Log log2 = new Log("子類靜態屬性"); public Child() { System.err.println("子類構造方法"); }}
在這兩個類中,我們分別在普通屬性、靜態屬性、靜態代碼塊和構造方法中進行資訊輸出,最後編寫測試類別進行測試:
package com.jianggujin.loadeorder;public class MainTest{ public static void main(String[] args) { new Child(); }}
運行程式,觀察控制台輸出資訊
通過控制台資訊,我們可以很直觀的看到類的載入以及屬性的初始化順序,我們總結一下,在JVM虛擬機器載入初始化JAVA類的順序為:
父類靜態屬性/父類靜態代碼塊->子類靜態代碼塊/子類靜態屬性->父類普通屬性->父類構造方法->子類普通屬性->子類構造方法
瞭解了類的載入順序,下面我們再來探討一下一個對象只聲明不賦值,與賦null值在實際使用中,有什麼區別,很多人會認為沒有被初始化的對象預設就為null,好像沒什麼區別,下面我們來看一個使用情境,在父類中有一個init()方法用於初始化的工作,並且該方法在父類的構造方法中進行調用,子類中重寫init()方法,在該方法中對子類成員變數進行初始化,我們來看看效果是否相同:
Parent.java
package com.jianggujin.loadeorder;public class Parent{ public Parent() { init(); } public void init() { }}
Child.java
package com.jianggujin.loadeorder;public class Child extends Parent{ Object obj1; Object obj2 = null; @Override public void init() { System.err.println("子類init方法"); obj1 = new Object(); obj2 = new Object(); }}
編寫測試方法進行測試:
package com.jianggujin.loadeorder;public class MainTest{ public static void main(String[] args) { Child child = new Child(); System.err.println(child.obj1); System.err.println(child.obj2); }}
觀察控制台,我們會看到類似如下的輸出:
java.lang.Object@15db9742
null
由此,我們可以發現只聲明不賦值,與賦null值還是有區別的。