一、JVM中類唯一性的確認
對於任意一個類,都需要由加載它的類加載器和這個類本身來確定其在JVM中的唯一性。
即:只有在兩個類是由同一個類加載器加載時,才能比較兩個類是否相等。
類相等包括:類的Class對象的equals()方法,isAssignableFrom()方法,isInstance()方法的返回結果,instanceof判定結果等。
二、兩種不同的類加載器:
1. 啓動類加載器——C++實現,是JVM自身的一部分。
2. 所有其他類加載器——Java實現,獨立於JVM存在,全都是抽象類java.lang.ClassLoader的子類。
虛擬機提供的3中類加載器:
1. 啓動類加載器(Bootstrap ClassLoader):
• 負責加載<JAVA_HOME>\lib目錄中的類或被參數-Xbootclasspath參數指定的路徑中的類(這些類一定要能被JVM識別)。
• 在定義自己的類加載器時,如果需要把加載請求委託給啓動類加載器,直接用null代替即可。
2. 擴展類加載器(Extension ClassLoader):
• 負責加載<JAVA_HOME>\lib\ext目錄中的類或被java.ext.dirs系統變量所指定的路徑中的所有類庫。
3. 應用程序類加載器(Application ClassLoader):
• 負責加載用戶路徑(ClassPath)上所指定的類庫,如果程序中沒有自定義過自己的類加載器,默認爲應用程序類加載器
• 這個類加載器是ClassLoader類中的getSystemClassLoader()方法的返回值,也稱爲“系統類加載器”。
三、雙親委派模型:
這裏的類加載器之間的父子關係不通過繼承實現,而是使用組合關係來複用父加載器的代碼。
雙親委派模型的工作機制:
• 一個類加載器收到了類的加載請求,會先把這個請求委託給父類加載器去完成,每一層的類加載器如此。
• 所有的加載請求都會傳送到頂層的啓動類加載器,只有當父加載器無法完成這一請求時,子類加載器纔會嘗試自己去加載。
**這種機制保證了Object類在程序的各種類加載器中都是同一個類,如果沒有雙親委派,用戶自己編寫一個java.lang.Object類,並放到ClassPath路徑中,那麼系統中會出現多個不同的Object類,Java體系則被破壞。
四、破壞雙親委派模型的方式:
1. 重寫loadClass()方法
2. 通過Thread類的setContextClassLoader()方法設置線程上下文類加載器
3. OSGI技術
• 雙親委派的具體邏輯都子啊loadClass()方法中實現,修改了loadClass()方法也就修改了雙親委派模型。
• Thread Context Class Loader線程上下文類加載器,如果線程創建時未設置此加載器,則會在父線程中繼承一個,默認時應用程序類加載器。可以實現JavaAPI對用戶代碼的調用操作。
• OSGI用於實現代碼的熱替換、模塊熱部署等操作,當收到類加載請求時,OSGI按如下順序進行搜索(只有前兩種情況符合雙親委派):
a. 將java.*開頭的類委託給父類加載器加載;
b. 將委派列表名單中的類委派給父類加載器加載;
c. 將Import列表中的類委派給Export這個類的Bundle的類加載器加載;
d. 查看當前Bundle的ClassPath,使用自己的類加載器加載;
e. 查找類是否在自己的FragmengBundle中,如果在,委託給FragmentBundle的類加載器加載;
f. 查找DynamicImport列表的Bundle,委派給對應的Bundle的類加載器加載
g. 都不存在,則失敗。