JVM中類加載的機制


虛擬機類加載機制

1,類與類加載器的關係java

一個類須要由加載它的類加載器和這個類自己一同來肯定這個類在Java虛擬機中的惟一性。
注:每個類加載器,都有一個獨立的類命名空間。

判斷兩個類是否相等:
	只有當兩個類是由同一個類加載器加載時,判斷它們是否相等纔有意義。
	若是兩個類不是由同一個類加載器加載的,即便這兩個類來源於同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不一樣,那麼這兩個類必定不相等。

2,雙親委派模型spa

要求:除了頂層的啓動類加載器外,其他的類加載器都有本身的父加載器。
	注意:類加載器間的父子關係不是以繼承的方式實現的,而是以組合關係的方式來複用父加載器的代碼。
原理:	若是一個類加載器收到了類加載的請求,它首先會把這個請求委派給父加載器去完成,每個層次的類加載器都是如此。
		所以,全部的加載請求最終都應該傳送到頂層的啓動類加載器中,只有當父加載器反饋本身沒法完成這個加載請求(在它的搜索範圍中沒有找到所需的類)時,子加載器纔會嘗試本身去加載。
好處:Java類型體系中最基礎的行爲獲得了保證,從而保證了Java程序的穩定運行。
	Java類隨着它的類加載器一塊兒具有了一種帶有優先級的層次關係。

3,系統提供的3種類加載器code

啓動類加載器(Bootstrap ClassLoader):負責將存放在 %JAVA_HOME%/lib 目錄中的類庫(如:rt.jar)加載到虛擬機內存中,用來加載Java的核心API。

擴展類加載器(Extension ClassLoader):負責加載%JAVA_HOME%/lib/ext 目錄中的類庫,用來加載Java的擴展API

應用程序類加載器(Application ClassLoader):負責加載用戶類路徑(ClassPath)中的類庫
	注:應用程序類加載器是java.lang.ClassLoader中getSystemClassLoader()方法的返回值。故又稱之爲:系統類加載器

4,ClassLoader加載流程對象

當運行一個程序時,JVM啓動,運行Bootstrap ClassLoader,該加載器加載了Java核心的API(Extension ClassLoader和Application ClassLoader也在此時被加載),
而後調用Extension ClassLoader加載擴展API,最後Application ClassLoader加載classpath下定義的Class

5,Class.forName和classloader繼承

目的:ClassLoader.loadClass()方法和Class.forName()方法的目的都是用來加載class的
區別:loadClass()方法在加載類的的時候並不對該類進行解析,所以不會初始化該類;而forName()方法在加載類的時候會將類進行解析和初始化。

ClassLoader.loadClass()方法
	protected Class<?> loadClass(String name, boolean resolve)
		name - 類的二進制名稱
		resolve - 是否解析這個類,默認爲false
	public Class<?> loadClass(String name)至關於:loadClass(name, false)

Class.forName()方法
	public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
		name - 所需類的徹底限定名
		initialize - 是否必須初始化類,默認爲true
		loader - 用於加載類的類加載器,默認爲當前類的類加載器
	public static Class<?> forName(String className)至關於:forName(className, true, currentLoader)

6,類加載的過程:裝載、鏈接、初始化內存

其中:鏈接分爲三步:驗證、準備、解析

裝載:找到相應的Class文件,讀入JVM
鏈接:
	1)驗證:驗證Class文件是否符合規定,確保Class文件中包含的信息符合當前虛擬機的要求。
	2)準備:爲類變量分配內存並設置類變量的默認初始值,這些變量所使用的內存都將在方法區中進行分配。
		注意:此時進行內存分配的只有類變量(static變量),不包括實例變量。實例變量會在對象實例化時隨着對象一塊兒分配在Java堆中。
	3)解析:將常量池中的符合引用替換爲直接引用。
初始化:類的初始化。

7,類初始化的時機:ssl

1)使用new關鍵字來實例化對象的時候、讀取或設置類的靜態字段(注:被final修飾、已在編譯期間把結果放入常量池的靜態字段除外),以及調用類的靜態方法時。
	注:子類引用父類的靜態字段,只會觸發父類的初始化而不會觸發子類的初始化。
2)使用java.lang.reflect包的方法對類進行反射調用的時候,若是類沒有進行過初始化,則須要先觸發其初始化
3)當初始化一個類的時候,若是發現其父類尚未初始化,則須要先觸發其父類的初始化
4)當虛擬機啓動時,用戶須要指定一個要執行的主類(包含main方法的類),虛擬機會先初始化這個主類

8,類的初始化順序get

初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)> 構造器
*對於靜態變量和靜態初始化塊之間、變量和初始化塊之間的前後順序:依照他們在類中的聲明順序進行初始化的

有繼承關係時:(父類的靜態變量、靜態初始化塊)>(子類的靜態變量、靜態初始化塊)>(父類變量、初始化塊)>(父類的構造器)>(子類變量、初始化塊)>(子類構造器)
*並非父類徹底初始化完畢後才進行子類的初始化,子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化以前就完成了
相關文章
相關標籤/搜索