轉自:https://yq.aliyun.com/articles/653204?utm_content=m_1000018740
先上桌結論:
父類靜態屬性(成員變量) > 父類靜態代碼塊 > 子類靜態屬性 > 子類靜態代碼塊 > 父類非靜態屬性 > 父類非靜態代碼塊 > 父類構造器 > 子類非靜態屬性 > 子類非靜態代碼塊 > 子類構造器
這么長怎么記呀?!
這里幫大家小結幾個特點:
- 靜態屬性和代碼塊,當且僅當該類在程序中第一次被 new 或者第一次被類加載器調用時才會觸發(不考慮永久代的回收)。也正是因為上述原因,類優先於對象 加載/new,即 靜態優先於非靜態。
- 屬性(成員變量)優先於構造方法,可以這么理解,加載這整個類,需要先知道類具有哪些屬性,並且這些屬性初始化完畢之后,這個類的對象才算是完整的。另外,非靜態代碼塊其實就是對象 new 的准備工作之一,算是一個不接受任何外來參數的構造方法。因此,屬性 > 非靜態代碼塊 > 構造方法。
- 有趣的是,靜態部分(前4個)是父類 > 子類,而 非靜態部分(后6個)也是父類 > 子類。
- 另外容易忽略的是,非靜態代碼塊在每次 new 對象時都會運行,可以理解:非靜態代碼塊是正式構造方法前的准備工作(非靜態代碼塊 > 構造方法)。
測試代碼如下:
public class test { static class A { static Hi hi = new Hi("A"); Hi hi2 = new Hi("A2"); static { System.out.println("A static"); } { System.out.println("AAA"); } public A() { System.out.println("A init"); } } static class B extends A { static Hi hi = new Hi("B"); Hi hi2 = new Hi("B2"); static { System.out.println("B static"); } { System.out.println("BBB"); } public B() { System.out.println("B init"); } } static class Hi { public Hi(String str) { System.out.println("Hi " + str); } } public static void main(String[] args) { System.out.println("初次 new B:"); B b = new B(); System.out.println(); System.out.println("第二次 new B:"); b = new B(); } }