一笼呆、Java中的ClassLoader是什么?
? ? ? ?當(dāng)寫好一個Java應(yīng)用程序奶栖,程序都是由若干個.class類文件組織而成的播演,當(dāng)程序在運行時蹬挤,即會調(diào)用該程序的一個入口函數(shù)來調(diào)用系統(tǒng)的相關(guān)功能障般,而這些功能都被封裝在不同的class文件當(dāng)中调鲸,所以經(jīng)常要從這個class文件中要調(diào)用另外一個class文件中的方法,如果另外一個文件不存在的挽荡,則會引發(fā)系統(tǒng)異常藐石。而程序在啟動的時候,并不會一次性加載程序所要用的所有class文件定拟,而是根據(jù)程序的需要于微,通過Java的類加載機制(ClassLoader)來動態(tài)加載某個class文件到JVM中,從而只有class文件被載入到了JVM之后青自,才能被其它class所引用株依。所以ClassLoader就是用來動態(tài)加載class文件到JVM當(dāng)中用的。
簡單的說Java中的ClassLoader就是加載 class 文件延窜,提供給程序運行時使用恋腕。
二、java中ClassLoader加載原理
1逆瑞、原理介紹
ClassLoader使用的是雙親委托模型來搜索類的吗坚,每個ClassLoader實例都有一個父類加載器的引用(不是繼承的關(guān)系,是一個包含的關(guān)系)呆万,虛擬機內(nèi)置的類加載器(Bootstrap ClassLoader)本身沒有父類加載器商源,但可以用作其它ClassLoader實例的的父類加載器。當(dāng)一個ClassLoader實例需要加載某個類時谋减。加載過程是:
? ? ?1.源 ClassLoader 先判斷該 Class 是否已加載牡彻,如果已加載,則直接返回 Class,如果沒有則委托給父類加載器庄吼。
? ? ?2.父類加載器判斷是否加載過該 Class缎除,如果已加載,則直接返回 Class总寻,如果沒有則委托給祖父類加載器器罐。
? ? ?3.依此類推,直到始祖類加載器(引用類加載器)渐行。
? ? ?4.始祖類加載器判斷是否加載過該 Class轰坊,如果已加載,則直接返回 Class祟印,如果沒有則嘗試從其對應(yīng)的類路徑下尋找 class 字節(jié)碼文件并載入肴沫。如果載入成功,則直接返回 Class蕴忆,如果載入失敗颤芬,則委托給始祖類加載器的子類加載器。
? ? 5.始祖類加載器的子類加載器嘗試從其對應(yīng)的類路徑下尋找 class 字節(jié)碼文件并載入套鹅。如果載入成功站蝠,則直接返回 Class,如果載入失敗卓鹿,則委托給始祖類加載器的孫類加載器沉衣。
? ?6.依此類推,直到源 ClassLoader减牺。
? ? 7.源 ClassLoader 嘗試從其對應(yīng)的類路徑下尋找 class 字節(jié)碼文件并載入豌习。如果載入成功,則直接返回 Class拔疚,如果載入失敗肥隆,源 ClassLoader 不會再委托其子類加載器,而是拋出異常稚失。
2栋艳、JVM中是如何判定兩個class是相同的呢?
? ? ? JVM在判定兩個class是否相同時句各,不僅要判斷兩個類名是否相同吸占,而且要判斷是否由同一個類加載器實例加載的。只有兩者同時滿足的情況下凿宾,JVM才認(rèn)為這兩個class是相同的矾屯。就算兩個class是同一份class字節(jié)碼,如果被兩個不同的ClassLoader實例所加載初厚,JVM也會認(rèn)為它們是兩個不同class件蚕。
? ? ?同一個Class = 相同的 ClassName + PackageName + ClassLoader
如果想了解更加具體請看如下鏈接:
JVM 的工作原理,層次結(jié)構(gòu)以及 GC 工作原理
三、Android 中的 ClassLoader
? ? Android 的 Dalvik(5.0之前版本)/ART(5.0增加的) 虛擬機如同標(biāo)準(zhǔn) Java 的 JVM 虛擬機一樣,也是同樣需要加載 class 文件到內(nèi)存中來使用排作,但是在 ClassLoader 的加載細節(jié)上會有略微的差別牵啦。
? ? Android打包之后的apk 應(yīng)用,將apk的后綴名改成zip或rar妄痪,解壓之后會看見有一個或多個 class.dex 文件哈雏,用多個dex文件是android使用了MultiDexApplication解決65535的問題。
android在安裝(installer)apk時衫生,就對dex會進行驗證和優(yōu)化裳瘪,同過一個專門的工具來處理,叫 DexOpt來進行處理障簿,處理之后會產(chǎn)生ODEX文件,運行Apk的時候栅迄,直接加載ODEX站故,避免重復(fù)驗證和優(yōu)化,加快了Apk的響應(yīng)時間毅舆。
總之西篓,Android 中的 Dalvik/ART 無法像 JVM 那樣直接加載 class 文件和 jar 文件中的 class,需要通過工具來優(yōu)化轉(zhuǎn)換成 Dalvik byte code 才行憋活,只能通過 dex 或者包含 dex 的jar岂津、apk 文件來加載(注意 odex 文件后綴可能是 .dex 或 .odex,也屬于 dex 文件)悦即,因此 Android 中的 ClassLoader 工作就交給了 BaseDexClassLoader 來處理吮成。
BaseDexClassLoader 及其子類
? 從ClassLoader的android源碼看ClassLoader是一個abstract類,其具體實現(xiàn)的子類有BaseDexClassLoader和SecureClassLoader辜梳。
? SecureClassLoader 的子類是URLClassLoader粱甫,其只能用來加載 jar 文件,這在 Android 的 Dalvik/ART 上沒法使用的作瞄。
? ?BaseDexClassLoader 的子類是PathClassLoader和DexClassLoader茶宵。
PathClassLoader
?PathClassLoader 在應(yīng)用啟動時創(chuàng)建,從 data/app/… 安裝目錄下加載 apk 文件
dexPath:文件或者目錄的列表宗挥,dex乌庶,apk,多個以文件分隔符分隔契耿,默認(rèn)是“.”
librarySearchPath:包含lib庫的目錄列表,多個以文件分隔符分隔瞒大,默認(rèn)是空格
parent:父類加載器
PathClassLoader 里面除了這 2 個構(gòu)造方法以外就沒有其他的代碼了,具體的實現(xiàn)都是在 BaseDexClassLoader 里面搪桂,其 dexPath 比較受限制糠赦,一般是已經(jīng)安裝應(yīng)用的 apk 文件路徑。
在 Android 中,App 安裝到手機后拙泽,apk 里面的 class.dex 中的 class 均是通過 PathClassLoader 來加載的淌山。
DexClassLoader
A class loader that loads classes from.jar and.apk files containing aclasses.dexentry. This can be used to execute code not installed as part of an application.
根據(jù)官方給出的文檔 DexClassLoader 可以從 SD 卡上加載包含 class.dex 的 .jar 和 .apk 文件,這也是插件化和熱修復(fù)的基礎(chǔ)顾瞻,在不需要安裝應(yīng)用的情況下泼疑,完成需要使用的 dex 的加載。
DexClassLoader類就只有一個方法荷荤,改方法有四個個參數(shù)
dexPath:dex文件路徑列表退渗,多個路徑使用”:”分隔
dexOutputDir:經(jīng)過優(yōu)化的dex文件(odex)文件輸出目錄
libPath:動態(tài)庫路徑(將被添加到app動態(tài)庫搜索路徑列表中)
parent:這是一個ClassLoader,這個參數(shù)的主要作用是保留java中ClassLoader的委托機制(優(yōu)先父類加載器加載classes蕴纳,由上而下的加載機制会油,防止重復(fù)加載類字節(jié)碼)
android的加載是根據(jù)BaseDexClassLoader子類進行加載不通的dex而子類的實現(xiàn)都在BaseDexClassLoader中,BaseDexClassLoader是關(guān)鍵古毛,下次分析BaseDexClassLoader源碼