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文件)。