類載入的全過程
類載入機制:
JVM把class檔案載入到記憶體,並對資料驚險校驗,解析和初始化,最終形成JVM可以直接使用的java型別的過程。
一、載入
JVM將class檔案位元組碼內容載入到記憶體,並將靜態的資料轉換成方法區中的執行時資料結構,在堆中生成一個代表這個類的java.lang.Class物件,作為方法區類資料的訪問入口。這個過程需要類載入器參與。
二、連結:將java類的二進位制程式碼合併到JVM的執行狀態之中的過程
1.驗證:確保載入的類資訊符合JVM規範,沒有安全方面的問題。
2.準備:正式為類變數(static變數)分配記憶體並設定類變數初始值的階段,這些記憶體都在方法區中進行分配。
3.解析:虛擬機器常量池內的符號引用替換成直接引用的過程
三、初始化
初始化階段是執行類構造器方法的過程,類構造器方法是由編譯器自動收集類中的所有變數的賦值動作動作和靜態語句塊的語句合併產生。
當初始化一個類的時候,如果其父類還沒有進行過初始化,需要先初始化其父類
虛擬機器會保證一個類的方法在多執行緒環境中被正確加鎖和同步。
四、類的引用
1.主動引用(一定會發生類的初始化):
a. new一個類的物件
b. 呼叫類的靜態成員和靜態方法
c. 使用java.lang.reflect包的方法對類進行反射呼叫
d. 當虛擬機器啟動,會先啟動main方法所在的類。
e. 當初始化一個類,如果其父類沒有被初始化,會先初始化它的父類
2.被動引用(不會發生類的初始化):
a.當訪問一個靜態域的時候,只有真正宣告這個域的類才會被初始化,通過子類引用父類的靜態變數,不會導致子類初始化
b.通過陣列定義類引用,不會觸發此類初始化
c.引用常量不會觸發此類的初始化
類載入器的層次結構:
a.引導類載入器 Bootstrap class loader
它用來載入 Java 的核心庫(JAVA_HOME/jre/lib/rt.jar,或sun.boot.class.path路徑下的內容),是用原生程式碼來實現的,並不繼承自 java.lang.ClassLoader。– 載入擴充套件類和應用程式類載入器。並指定他們的父類載入器。
b.擴充套件類載入器 extension class loader
用來載入 Java 的擴充套件庫(JAVA_HOME/jre/ext/*.jar,或java.ext.dirs路徑下的內容) 。Java 虛擬機器的實現會提供一個擴充套件庫目錄。該類載入器在此目錄裡面查詢並載入 Java類。
c.應用程式類載入器 application class loader
它根據 Java 應用的類路徑(classpath,java.class.path 路徑下的內容)來載入 Java 類。一般來說,Java 應用的類都是由它來完成載入的。
d.自定義載入器 java.lang.Classloader
通過繼承 java.lang.ClassLoader類的方式實現自己的類載入器,以滿足一些特殊的需求。
類載入器的代理模式
代理模式----交給其他的載入器來載入指定的類
雙親委託機制------就是某個特定的類載入器在接到載入類的請求是,先將載入任務委託給父類載入器,一直追溯到頂,如果超類能載入完成,就直接返回成功,如果超類不能完成就自己去載入類。
這種機制保證了不會出現使用者自己能定義java.lang.object類的情況。
但並不是所有的類載入器都採用這個雙親委託機制
如tomcat就跟它不一樣,它會先去自己載入,載入不成功再找它的超類來載入
自定義類載入器的流程:
1、首先檢查請求的型別是否已經被這個類裝載器裝載到名稱空間中了,如果已經裝載,直接返回;否則轉入步驟2 2、委派類載入請求給父類載入器(更準確的說應該是雙親類載入器,真個虛擬機器中各種類載入器最終會呈現樹狀結構),如果父類載入器能夠完成,則返回父類載入器載入的Class例項;否則轉入步驟3 3、呼叫本類載入器的findClass(…)方法,試圖獲取對應的位元組碼,如果獲取的到,則呼叫defineClass(…)匯入型別到方法區;如果獲取不到對應的位元組碼或者其他原因失敗,返回異常給loadClass(…), loadClass(…)轉拋異常,終止載入過程(注意:這裡的異常種類不止一種)。 注意:被兩個類載入器載入的同一個類,JVM不認為是相同的類。