JVM中類加載的機制

 

-----------------------------------------------------------------------
虛擬機類加載機制
-----------------------------------------------------------------------
1,類與類加載器的關係
	
	一個類需要由加載它的類加載器和這個類本身一同來確定這個類在Java虛擬機中的唯一性。
	注:每一個類加載器,都有一個獨立的類命名空間。
	
	判斷兩個類是否相等:
		只有當兩個類是由同一個類加載器加載時,判斷它們是否相等纔有意義。
		如果兩個類不是由同一個類加載器加載的,即使這兩個類來源於同一個Class文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那麼這兩個類一定不相等。

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

		
3,系統提供的3種類加載器
	啓動類加載器(Bootstrap ClassLoader):負責將存放在 %JAVA_HOME%/lib 目錄中的類庫(如:rt.jar)加載到虛擬機內存中,用來加載Java的核心API,由本地代碼(C)編寫。

	擴展類加載器(Extension ClassLoader):負責加載%JAVA_HOME%/lib/ext 目錄中的類庫,用來加載Java的擴展API
		源碼:rt.jar中的sun.misc.Launcher.ExtClassLoader類。
	
	應用程序類加載器(Application ClassLoader):負責加載用戶類路徑(ClassPath)中的類庫。
		源碼:rt.jar中的sun.misc.Launcher.AppClassLoader類。
		注:AppClassLoader是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,類初始化的時機:
	1)使用new關鍵字來實例化對象的時候、讀取或設置類的靜態字段(注:被final修飾、已在編譯期間把結果放入常量池的靜態字段除外),以及調用類的靜態方法時。
		注:子類引用父類的靜態字段,只會觸發父類的初始化而不會觸發子類的初始化。
	2)使用java.lang.reflect包的方法對類進行反射調用的時候,如果類沒有進行過初始化,則需要先觸發其初始化
	3)當初始化一個類的時候,如果發現其父類還沒有初始化,則需要先觸發其父類的初始化
	4)當虛擬機啓動時,用戶需要指定一個要執行的主類(包含main方法的類),虛擬機會先初始化這個主類


8,類的初始化順序
	初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)> 構造器
	*對於靜態變量和靜態初始化塊之間、變量和初始化塊之間的先後順序:依照他們在類中的聲明順序進行初始化的
	
	有繼承關係時:(父類的靜態變量、靜態初始化塊)>(子類的靜態變量、靜態初始化塊)>(父類變量、初始化塊)>(父類的構造器)>(子類變量、初始化塊)>(子類構造器)
	*並不是父類完全初始化完畢後才進行子類的初始化,子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化之前就完成了


	

9,查看jar包中是否包含某個類:	jar -tf test.jar | grep 類名




====




 

 

 

發佈了298 篇原創文章 · 獲贊 56 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章