天天看點

Java類的加載過程和順序

首先,我們得了解 類什麼時候加載,和 類什麼時候初始化。

  1. 類什麼時候加載

    類的加載是通過類加載器(Classloader)完成的,它既可以是餓漢式[eagerly load](隻要有其它類引用了它就加載)加載類,也可以是懶加載 [lazy load](等到類初始化發生的時候才加載)。不過我相信這跟不同的JVM實作有關。

    然而他又是受JLS保證的(當有靜态初始化需求的時候才被加載)。

  2. 類的加載順序:

    ① 父類靜态塊–子類靜态塊–父類初始化塊–父類構造方法–子類初始化塊–子類構造方法

    ② 靜态塊—main()—初始化構造塊-----構造方法(簡化版)

  3. 類什麼時候初始化

    加載完類後,類的初始化就會發生,意味着它會初始化所有類靜态成員,以下情況一個類被初始化:

    執行個體通過使用 new()關鍵字建立 或者 使用class.forName()反射,但它有可能導緻ClassNotFoundException。

    類的靜态方法被調用

    類的靜态域被指派

    靜态域被通路,而且它不是常量

    在頂層類中執行assert語句

    clone方式:clone隻是複制拷貝(深拷貝需要new,淺拷貝不需要,原來的對象的改變不反應在拷貝對象上)

    反序列化:readObject是從檔案中還原對象

    反射同樣可以使類初始化,比如java.lang.reflect包下面的某些方法,JLS嚴格的說明:一個類不會被任何除以上之外的原因初始化。

  4. 類是如何被初始化的

    現在我們知道什麼時候觸發類的初始化了,他精确地寫在Java語言規範中。但了解清楚 域(fields,靜态的還是非靜态的)、塊(block靜态的還是非靜态的)、不同類(子類和超類)和不同的接口(子接口,實作類和超接口)的初始化順序也很重要類。事實上很多核心Java面試題和SCJP問題都是基于這些概念,下面是類初始化的一些規則:

    類從頂至底的順序初始化,是以聲明在頂部的字段的早于底部的字段初始化

    超類早于子類和衍生類的初始化

    如果類的初始化是由于通路靜态域而觸發,那麼隻有聲明靜态域的類才被初始化,而不會觸發超類的初始化或者子類的初始化即使靜态域被子類或子接口或者它的實作類所引用。

    接口初始化不會導緻父接口的初始化。

    靜态域的初始化是在類的靜态初始化期間,非靜态域的初始化時在類的執行個體建立期間。這意味這靜态域初始化在非靜态域之前。

    非靜态域通過構造器初始化,子類在做任何初始化之前構造器會隐含地調用父類的構造器,他保證了非靜态或執行個體變量(父類)初始化早于子類

    4.1 類的初始化過程:

    初始化父類靜态變量、靜态代碼塊,

    初始化子類靜态變量、靜态代碼塊,

    初始化父類普通成員變量、代碼塊、父類構造方法,

    初始化子類普通成員變量、代碼塊、子類構造方法,

Java中對字段屬性是靜态綁定(編譯出錯),方法成員是動态綁定(運作出錯)。