Java類的加載和初始化

為什么說Java是跨平臺語言

Java語言的運行環(huán)境是在Java虛擬機中。 Java虛擬機消除了各個平臺之間的差異,只要操作系統(tǒng)平臺下安裝了Java虛擬機,那么使用Java開發(fā)的東西都能在其上面運行。如下圖所示:



Java虛擬機對各個平臺而言,實質上是一個可執(zhí)行程序。例如在windows平臺下,java虛擬機就是一個java.exe進程而已。

JVM虛擬機啟動和加載類過程

下面以一個簡單的java程序,分析虛擬機啟動過程。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}

當我們運行上面程序時,將會啟動一個虛擬機進程,不管Java程序有多么復雜,啟動了多少線程,它們都將處于該Java虛擬機進程里。具體過程如下:

1、根據(jù)JVM的內存配置,為JVM申請?zhí)囟ù笮〉膬却婵臻g

2、創(chuàng)建一個引導類加載器實例

JVM申請好內存空間后,JVM會創(chuàng)建一個引導類加載器(Bootstrap Classloader)實例,引導類加載器是使用C++實現(xiàn)的,負責加載JVM虛擬機運行時所需的基本系統(tǒng)級別的類,如java.lang.String, java.lang.Object等。引導類加載器(Bootstrap Classloader)會讀取 {JRE_HOME}/lib 下的jar包和配置,然后將這些系統(tǒng)類加載到方法區(qū)內。

方法區(qū)用于存儲已經被虛擬機加載過的類信息、常量、靜態(tài)變量、即時編譯器編譯出的代碼等數(shù)據(jù)。


Class是一個實實在在的類,在包 java.lang 下。它跟我們自己定義的類一樣,是一個實實在在的類,Class對象就是這個Class類的實例了。在Java里,所有的類的根源都是Object類,Class也不例外,它是繼承自Object的一個特殊的類,它內部可以記錄類的成員、接口等信息。

3、創(chuàng)建JVM 啟動器實例 Launcher,并取得類加載器ClassLoader

上述步驟完成,JVM基本運行環(huán)境就準備就緒了。此時,JVM虛擬機會調用已經加載在方法區(qū)的類sun.misc.Launcher 的靜態(tài)方法getLauncher(), 獲取sun.misc.Launcher 實例:

sun.misc.Launcher launcher = sun.misc.Launcher.getLauncher(); //獲取Java啟動器
ClassLoader classLoader = launcher.getClassLoader();          //獲取類加載器ClassLoader用來加載class到內存來

sun.misc.Launcher 使用了單例模式設計,保證一個JVM虛擬機內只有一個sun.misc.Launcher實例。在Launcher的內部,其定義了兩個類加載器(ClassLoader),分別是sun.misc.Launcher.ExtClassLoader和sun.misc.Launcher.AppClassLoader,這兩個類加載器分別被稱為拓展類加載器(Extension ClassLoader) 和 應用類加載器(Application ClassLoader).如下圖所示:



此時的 launcher.getClassLoader() 方法將會返回 AppClassLoader實例。
當AppClassLoader加載類時,會首先嘗試讓父加載器ExtClassLoader進行加載,如果父加載器ExtClassLoader加載成功,則AppClassLoader直接返回父加載器ExtClassLoader加載的結果;
如果父加載器ExtClassLoader加載失敗,AppClassLoader則會判斷該類是否是引導的系統(tǒng)類(即是否是通過Bootstrap類加載器加載,這會調用Native方法進行查找);
若要加載的類不是系統(tǒng)引導類,那么ClassLoader將會嘗試自己加載,加載失敗將會拋出“ClassNotFoundException”。

上面討論的應用類加載器AppClassLoader的加載類的模式就是我們常說的雙親委派模型(parent-delegation model).
對于某個特定的類加載器而言,應該為其指定一個父類加載器,當用其進行加載類的時候:

  1. 委托父類加載器幫忙加載;
  2. 父類加載器加載不了,則查詢引導類加載器有沒有加載過該類;
  3. 如果引導類加載器沒有加載過該類,則當前的類加載器應該自己加載該類;
  4. 若加載成功,返回 對應的Class<T> 對象;若失敗,拋出異?!癈lassNotFoundException”。

4、使用類加載器ClassLoader加載HelloWorld類

通過 launcher.getClassLoader()方法返回AppClassLoader實例,接著就是AppClassLoader加載HelloWorld類的時候了。

5、加載完成時候JVM會執(zhí)行HelloWorld類的main方法入口

6、java程序運行結束,JVM銷毀

類的初始化

在Java類中對類變量指定初始值有兩種方式,一是聲明類變量時指定初始值;二是使用靜態(tài)初始化塊為類變量指定初始值。
JVM會按照這些語句在程序中的排列順序依次執(zhí)行它們。另外,如果類的父類還沒初始化,會先初始化父類。例如下面的類:

public class Test {
    static {
        b = 6;
        System.out.println("---------");
    }
    static int a = 5;
    static int b = 9;
    static int c;

    public static void main(String[] args) {
        System.out.println(Test.b);//結果為9
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容