類的初始化
主動引用【會初引發始化】
-
-
二、訪問某個類或接口的靜態變量,或者對該靜態變量賦值。
-
-
四、使用java.lang.reflect包下的方法對類進行反射調用的時候
-
五、初始化一個類的子類時,發現其父類未初始化,優先初始化父類
-
六、虛擬機啓動的時候,用戶須要指定一個主類,好比Main方法類,虛擬機會優先初始化這個主類。
-
七、JDK1.7開始提供的動態語言支持,當java.lang.invoke.MethodHandler實例後的結果是REF-getStatic/REF_putstatic/REF_invokeStatic的句柄,而且這些句柄對應的類沒初始化的話應該首先初始。
總結:只有當程序訪問的靜態變量或靜態方法確實在當前類或當前接口中定義時,才能夠認爲是對類或接口的主動使用java
被動引用【不會引發初始化】
-
一、經過子類來引用父類的靜態字段,只會觸發父類的初始化,不會觸發子類的初始化。
-
二、經過數組定義來引用類,不會觸發此類的初始化。SuperClass[] superClasses = new SuperClass[10]
-
三、引用一個類的靜態常量也不會觸發初始化,由於常量在編譯階段已經確認。public static final int value = 22;
接口初始化
-
一、當Java虛擬機初始化一個類時,要求它的全部父類都已經被初始化,可是這條規則並不適用於接口。
-
二、在初始化一個類時,並不會先初始化它實現的接口。
-
-
四、一個父類接口並不會由於它的子類接口或者實現類的初始化而初始化,只有當程序首次使用特定接口的靜態變量時,纔會致使該接口的初始化。
類的生命週期
加載
經過一個類全限定名來獲取此類的二進制字節流。將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構。在內存中生成一個類表明這個類的java.lang.Class對象,做爲方法區這個類的各類數據訪問入口。web
靜態變量是怎麼加載的?數組
查找並加載類的二進制數據,就是把二進制形式的Java類型讀入Java虛擬機。數據結構
鏈接
驗證
-
文件格式驗證:字節流是否符合class文件格式的規範。
-
-
-
符號引用驗證:常量池的各類符號引用信息進行匹配性校驗。
準備
在準備階段,Java虛擬機爲類的靜態變量分配內存,並將其初始爲默認值。爲類變量分配內存,設置默認值,可是在到達初始化以前,爲類變量都沒有初始化爲正真的初始值。例如對於如下Fruit類,在準備階段,將爲int類型的靜態變量a分配4個字節的內存空間,而且賦予默認值0,爲long類型的靜態變量b分配8個字節的內存空間,而且賦值爲默認值0.編輯器
【代碼片斷】
class Fruit{ public static int a = 1; public static long b; public static long c; static { b = 2L; } } 複製代碼
解析
把類中的符號引用轉化爲直接引用,解析過程就是在類型的常量池中尋找類、接口、字段和方法的符號引用,把這些符號引用替換爲直接引用的過程。ui
初始化
對類的靜態變量,靜態代碼塊執行初始化操做,爲類變量賦於正確的初始值。url
在初始化階段,Java虛擬機執行類的初始化語句,爲類的靜態變量賦於初始值。在程序中,靜態變量的初始化有兩種途徑:(1)在靜態變量的聲明處進行初始化(2)在靜態代碼塊中進行初始化。例如【上面的代碼片斷】中,靜態變量a和b都被顯示初始化,而靜態變量c沒有被顯示初始化,它將保持默認值0.spa
靜態變量的聲明語句,以及靜態代碼塊都被看做類的初始化語句,Java虛擬機會按照初始化語句在類文件中的前後順序來依此執行它們,例如 public static int a = 6;初始化之後這個靜態變量a的取值爲4.code
類的初始化步驟cdn
-
假如這個類尚未被加載和鏈接,那就先進行加載和鏈接。
-
假如類存在直接父類,而且這個父類尚未被初始化,那就先初始化直接父類。
-
假如類中存在初始化語句,那就依次執行這些初始化語句。
使用
卸載
清除該類的實例.
清除該類的ClassLoader引用.
清除該class對象的引用
舉個栗子🌰
-
問:public static int i = 100 怎麼賦值的?
-
答:一、準備階段賦分配內存並將初始值爲0. 二、初始化階段賦值爲100.
Class對象獲取方式及是否引發初始化
-
Class clazz1 = 類名.class 沒有完成初始化過程.
-
Class clazz2 = 類名.class.getClassLoader().loadClass("全限定名");沒有完成初始化過程.
-
Class clazz3 = Class.forName("全限定名")完成初始化過程.
-
Class clazz4 = 對象引用.getClass(); 對象存在了,完成了初始化過程.
四種方式的不一樣點爲有沒有初始化。
腦圖
大佬,看都看到這了,不關注一個再走🍻🍻 