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
初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)> 構造器 *對於靜態變量和靜態初始化塊之間、變量和初始化塊之間的前後順序:依照他們在類中的聲明順序進行初始化的 有繼承關係時:(父類的靜態變量、靜態初始化塊)>(子類的靜態變量、靜態初始化塊)>(父類變量、初始化塊)>(父類的構造器)>(子類變量、初始化塊)>(子類構造器) *並非父類徹底初始化完畢後才進行子類的初始化,子類的靜態變量和靜態初始化塊的初始化是在父類的變量、初始化塊和構造器初始化以前就完成了