ClassLoader雙親代理模型加載類的特色及做用
JVM以及Dalvik均是經過ClassLoader加載類,其源碼以下
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
suppressed = e;
}
if (clazz == null) {
try {
clazz = findClass(className);
} catch (ClassNotFoundException e) {
e.addSuppressed(suppressed);
throw e;
}
}
}
return clazz;
}
從源碼分析可知loadClass方法先判斷是否被loaded過,沒有則經過parent加載,如此遞歸向上,稱之位雙親委託。若是繼承向上的路線中均沒有被加載,才由當前ClassLoader負責加載。
特色:若某個類被根節點加載過,則在之後系統的整個生命週期內不會被從新加載。
做用:
1.共享:Framework層級的類一旦被根節點加載就緩存在內存,之後不需從新加載。
2.隔離:不一樣繼承路線上的classLoader加載的類確定不是同一個類,這樣作可避免冒充核心庫類,從而訪問核心庫包可見成員。例如,用戶沒法經過自定義java.lang.String類,來把系統的String類給替換掉。
Android應用中的ClassLoader對象
在Activity的onCreate方法中調用
ClassLoader classLoader = getClassLoader();
if (classLoader != null) {
lg.e("當前類對應的ClassLoader:" + classLoader.toString());
while (classLoader.getParent() != null) {
classLoader = classLoader.getParent();
lg.e("上個ClassLoader的父親:" + classLoader.toString());
}
}
輸出結果以下,
其中,BootClassLoader在系統啓動時建立,PathClassLoader在應用啓動時建立,用於加載/data/app/com.coca.androidunitylab-1.apk。所以在一個應用中至少有兩個classLoader。
DexClassLoader與PathClassLoader的異同
適用場景:
DexClassLoader能夠加載jar/apk/dex,能夠從SD卡中加載未安裝的apk;
PathClassLoader只能加載系統中已經安裝過的apk;
二者的區別在於
optimizedDirectory參數,其在
BaseDexClassLoader構造方法中用於構建
DexPathList對象。
optimizedDirectory用來緩存須要加載的dex文件,並建立一個DexFile對象;若是它爲null,那麼會直接使用dex文件原有的路徑來建立DexFile對象。
optimizedDirectory必須是內部存儲路徑,
DexClassLoader因爲能夠指定
optimizedDirectory,從而能夠加載外部dex,在使用的時候被複制到內部路徑
optimizedDirectory內;而
PathClassLoader沒指定
optimizedDirectory,所以只能加載內部dex文件(即已經安裝的apk文件)。