Android類加載(一)——DVM僚纷、ART烫扼、Dexopt、DexAot名詞解析
Android類加載(二)——雙親委托機制
Android類加載(三)——源碼解讀
Java類加載器
定義
- BootClassLoader
用于加載Android FrameWork層的class文件(系統(tǒng)的Activity) - PathClassLoader
用于加載Android應(yīng)用程序的class 文件(自己寫的MainActivity)
也可以加載指定的dex浩考,以及jar廊移、zip、apk中的classes.dex - DexClassLoader
加載指定的dex舵鳞,以及jar震檩、zip、apk中的classes.dex
比較PathClassLoader和DexClassLoader
- 在一個app安裝的過程中蜓堕,Android系統(tǒng)是沒有用到DexClassLoader類的抛虏,而PathClassLoader會被用于加載Android應(yīng)用程序的class 文件(例如自己寫的MainActivity),DexClassLoader類就是提供給開發(fā)者使用的類套才,Android FrameWork層并沒有使用到DexClassLoader迂猴。
- 構(gòu)造方法的區(qū)別
public class DexClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code DexClassLoader} that finds interpreted and native
* code. Interpreted classes are found in a set of DEX files contained
* in Jar or APK files.
*
* <p>The path lists are separated using the character specified by the
* {@code path.separator} system property, which defaults to {@code :}.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param optimizedDirectory directory where optimized dex files
* should be written; must not be {@code null}
* @param libraryPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
public class PathClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code PathClassLoader} that operates on a given list of files
* and directories. This method is equivalent to calling
* {@link #PathClassLoader(String, String, ClassLoader)} with a
* {@code null} value for the second argument (see description there).
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param parent the parent class loader
*/
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
/**
* Creates a {@code PathClassLoader} that operates on two given
* lists of files and directories. The entries of the first list
* should be one of the following:
*
* <ul>
* <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
* well as arbitrary resources.
* <li>Raw ".dex" files (not inside a zip file).
* </ul>
*
* The entries of the second list should be directories containing
* native library files.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param libraryPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
}
從源碼里可以看出它們都派生于BaseDexClassLoader類,但在它們的構(gòu)造方法稍有不同
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
有三個參數(shù)是一樣的
- dexPath:要加載的dex所在的目錄
- libraryPath:Native方法so文件所在的目錄
- parent:可以理解為雙親加載機制里的所謂的“父親”(雙親委托機制下面再講)
- optimizedDirectory:opt優(yōu)化后的dex文件所在的目錄(而且從源碼的注釋里可以看到背伴,這個目錄必須為私有目錄沸毁,不能為sd卡的目錄)
而DexClassLoader就比PathClassLoader多了一個optimizedDirectory參數(shù),
也就是說DexClassLoader用于存儲opt優(yōu)化后的dex文件的保存路徑可以自己定義傳進去傻寂,而PathClassLoader存儲opt優(yōu)化后的dex文件的保存路徑是系統(tǒng)默認的息尺。僅此這個區(qū)別而已。
雙親委托機制
類加載在加載類時疾掰,首先將加載任務(wù)委托給父類加載器加載搂誉,依次遞歸,如果父類加載器可以完成加載任務(wù)静檬,就成功返回炭懊,如果父類加載器無法完成或者沒有父類加載器時,才自己去加載拂檩。
簡單一個詞語概括:啃老族機制侮腹。
下面我們用一段代碼來進行解釋:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//PathClassLoader
ClassLoader classLoader = this.getClassLoader();
//BootClassLoader
ClassLoader classLoader1 = Activity.class.getClassLoader();
System.out.println("PathClassLoader getClassLoader:"+classLoader);
System.out.println("PathClassLoader getClassLoader 的父親 :"+classLoader.getParent());
System.out.println("BootClassLoader Activity.class :"+classLoader1);
從打印中我們可以得出以下結(jié)論
- MainActivity的類加載器是PathClassLoader
- Activity的類加載器是PathClassLoader
- PathClassLoader的父親是BootClassLoader
注意:這里所說的父親并不是指這個類的父類(BaseDexClassLoader),只是ClassLoder類里的一個類型為ClassLoader的成員變量名稱叫做parent
那么為什么要使用雙親委托機制呢稻励?
在我們應(yīng)用程序啟動的時候父阻,BootClassLader會去加載FrameWork層的所有的類,例如上面的Activity钉迷,而我們自己寫的代碼BootClassLader是沒辦法去加載的至非,只能由PathClassLoader去加載,因為我們自己寫的代碼的類糠聪,在我們的apk里面荒椭,不在系統(tǒng)里面,例如上面的MainActivity舰蟆。但現(xiàn)在我們寫的MainActivity是派生于AppCompatActivity的趣惠,AppCompatActivity屬于FrameWork層的類狸棍,已經(jīng)被BootClassLader加載了,如果我們不使用雙親委托機制的話味悄,PathClassLoader是不是加載不到FrameWork層的類草戈,那是不是加載不了AppCompatActivity了,而運用雙親委托機制就能很好的讓不同的類加載器去分別執(zhí)行不同層級的類加載的任務(wù)侍瑟,這樣也是有利于系統(tǒng)的安全性唐片,對于開發(fā)者來說你是無法知道怎么去加載系統(tǒng)的類的,你永遠只能加載自己寫的類涨颜,系統(tǒng)層面的類是不讓你去加載的费韭,只能由父親BootClassLader去加載。