天天看點

類加載器(classLoader)

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");  
    }