1. 類的初始化
Java類從class檔案到可以生成對象,需要經曆類的加載、連接配接和初始化。
依次說明下:
(1)類的加載:
查找并加載類的二進制資料,即:将類的.class檔案中的二進制資料讀入到記憶體中,将其放在運作時 資料區的方法區内,然後在堆區建立一個java.lang.Class對象,用來封裝類在方法區内的資料結構。(說明下:此處所說的方法區就是指JVM啟動時配置設定的一塊記憶體區域,其大小預設為64M,可以通過-XX:PermSize指定,即人們常說的永久代)。此處還需要補充的是當我們的類加載時就已經在堆中生成了Class對象,也就意味着該類的所有對象都共享這一個Class對象,它由jvm自動生成,我們不能生成。
(2)連接配接:
具體包括三個步驟:
驗證:確定被加載的類的正确性
準備:為類的靜态變量配置設定記憶體,并初始化為預設值
解析:把類中的符号引用轉換為直接引用(具體含義不太清楚,請高手指教)
(3)初始化:
為類的靜态變量賦予正确的初始值
2. 什麼時候初始化?
這個最容易想到的就是我們new對象的時候,再深入一點就是通路靜态變量,仔細想想還有其他的麼?呵呵~~ 具體總結如下:
就是一句話:當Java程式對類主動使用時就進行初始化。那什麼叫對類的主動使用呢?如下6中情況就是對類主動使用,除了這六種情況,都是對類的被動使用,不會導緻類的初始化。
主動使用:
1) 建立類的執行個體,這是最容易想到的情況
2) 通路類的靜态變量,給靜态變量指派。重要:通路的是編譯時常量,則不會導緻類的初始化。
3) 通路類的靜态方法
4) 反射,如:Class.forName(); 典型的例子是擷取JDBC連接配接時必須先要初始化JDBC驅動。
5) 初始化一個類的子類。(關于類的詳細初始化順序見下文)
6)JVM啟動時被标明為啟動類的類,這個不太常見
3. 類的加載和初始化的差別:
說了這麼多,有些人可能有點聽糊塗了,這兩個到底有什麼差別呢?關于類的加載是這樣的:JVM規範允許類加載器在預料某個類将要被使用時就預先加載它,如果在預先加載的過程中遇到了.class檔案錯誤,暫時不會報錯,等真正要使用該類的時候才抛出錯誤。
由此可以看出來,類的加載并不是确定的、可控的。而初始化則是确定的,即隻有對類的主動使用時才會導緻類的初始化。
4. 類是如何被加載的
兩種類型的類加載器:
java虛拟機自帶的加載器
根類加載器(Bootstrap): 負責加載核心類庫
擴充類加載器(Extension): 它的父加載器為BootStrap,它用來加載jdk/jre/lib/ext下的類庫,它是java.lang.ClassLoader的子類
系統類加載器(應用加載器)(System): 它的父加載器為Extension, 它從環境變量classpath或者系統屬性java.class.path所指定的目錄中加載類。它是使用者自定義加載器的預設父加載器。
父子加載器并非繼承關系。也就是說子加載器不一定是父加載器的子類。
自定義的加載器必須要繼承java.lang.ClassLoader
5. 類的完整初始化過程:
1) 類的加載(在方法區中建立Class對象
2) 類的連接配接(驗證、準備、解析)
3) 父類靜态變量按照順序初始化
4) 子類靜态變量按照順序初始化
5) 父類成員變量按照順序初始化
6) 父類構造器初始化
7) 子類成員變量變量按照順序初始化
8) 子類構造器初始化
9) 初始化完成
6) 附一個阿裡筆試題,關于初始化的,如果第一次就能答對,那說明對Java初始化就掌握得非常好了
public class AliTest {
public static int k = 0;
public static AliTest s1 = new AliTest("s1");
public static AliTest s2 = new AliTest("s2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("構造塊");
}
static {
print("靜态塊");
}
public static int print(String s) {
System.out.println(++k + ":" + s + "\ti=" + i + "\tn=" + n);
++n;
return ++i;
}
public AliTest(String s) {
System.out.println(++k+":"+s+"\ti="+i+"\tn="+n);
++i;
++n;
}
public static void main(String[] args) {
new AliTest("init");
}