国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

詳解Android類加載ClassLoader

2019-10-23 18:30:15
字體:
來源:轉載
供稿:網友

基本知識

Java的類加載設計了一套雙親代理的模式,使得用戶沒法替換系統的核心類,從而讓應用更安全。所謂雙親代理就是指,當加載類的時候首先去Bootstrap中加載類,如果沒有則去Extension中加載,如果再沒有才去AppClassLoader中去加載。從而實現安全和穩定。

Java ClassLoader

BootstrapClassLoader

引導類加載器 ,用來加載Java的核心庫。通過底層代碼來實現的,基本上只要parent為null,那就表示引導類加載器。

比如:charsets.jar、deploy.jar、javaws.jar、jce.jar、jfr.jar、jfxswt.jar、jsse.jar、management-agent.jar、plugin.jar、resources.jar、rt.jar

ExtClassLoader

拓展類加載器 ,用來加載Java的拓展的類庫, ${JAVA_HOME}/jre/lib/ext/ 目錄中的所有jar。

比如:cldrdata.jar、dnsns.jar、jfxrt.jar、localedata.jar、nashorn.jar、sunec.jar、sunjce_provider.jar、sunpkcs11.jar、zipfs.jar等等

AppClassLoader

系統類加載器 (不要被名字給迷惑),用來加載Java應用中的類。一般來說自己寫的類都是通過這個加載的。而Java中 ClassLoader.getSystemClassLoader() 返回的就是AppClassLoader。(Android中修改了ClassLoader的邏輯,返回的會是一個PathClassLoader)

自定義ClassLoader

用戶如果想自定義ClassLoader的話,只需要繼承自 java.lang.ClassLoader 即可。

ClassLoader中與加載類相關的方法:

  1. getParent() 返回該類加載器的父類加載器。
  2. loadClass(String name) 加載名稱為 name的類,返回的結果是 java.lang.Class類的實例。
  3. findClass(String name) 查找名稱為 name的類,返回的結果是 java.lang.Class類的實例。
  4. findLoadedClass(String name) 查找名稱為 name的已經被加載過的類,返回的結果是 java.lang.Class類的實例。
  5. defineClass(String name, byte[] b, int off, int len) 把字節數組 b中的內容轉換成 Java 類,返回的結果是 java.lang.Class類的實例。這個方法被聲明為 final的。

也許你不太了解上面幾個函數的區別,沒關系,我們來看下源碼是如何實現的。

//ClassLoader.javaprotected Class<?> loadClass(String name, boolean resolve)  throws ClassNotFoundException{    // First, check if the class has already been loaded    Class c = findLoadedClass(name);    if (c == null) {      long t0 = System.nanoTime();      try {        if (parent != null) {          c = parent.loadClass(name, false);        } else {          c = findBootstrapClassOrNull(name);        }      } catch (ClassNotFoundException e) {        // ClassNotFoundException thrown if class not found        // from the non-null parent class loader      }      if (c == null) {        // If still not found, then invoke findClass in order        // to find the class.        long t1 = System.nanoTime();        c = findClass(name);        // this is the defining class loader; record the stats      }    }    return c;}

所以優先級大概如下:

loadClass → findLoadedClass → parent.loadClass/findBootstrapClassOrNull → findClass → defineClass

Android ClassLoader

在Android中ClassLoader主要有兩個直接子類,叫做 BaseDexClassLoader 和 SecureClassLoader 。而前者有兩個直接子類是 PathClassLoader 和 DexClassLoader (Android O添加了 InMemoryDexClassLoader ,略)。

我們只討論PathClassLoader和DexClassLoader

PathClassLoader

用來加載安裝了的應用中的dex文件。它也是Android里面的一個最核心的ClassLoader了。相當于Java中的那個AppClassLoader。

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 librarySearchPath 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 librarySearchPath, ClassLoader parent) {    super(dexPath, null, librarySearchPath, parent);  }}

它的實例化是通過調用 ApplicationLoaders.getClassLoader 來實現的。

它是在ActivityThread啟動時發送一個BIND_APPLICATION消息后在handleBindApplication中創建ContextImpl時調用LoadedApk里面的 getResources(ActivityThread mainThread) 最后回到ActivityThread中又調用LoadedApk的 getClassLoader 生成的,具體的在LoadedApk的 createOrUpdateClassLoaderLocked

那么問題來了,當Android加載class的時候,LoadedApk中的ClassLoader是怎么被調用到的呢?

其實Class里面,如果你不給ClassLoader的話,它默認會去拿Java虛擬機棧里面的 CallingClassLoader ,而這個就是LoadedApk里面的同一個ClassLoader。

//Class.javapublic static Class<?> forName(String className)      throws ClassNotFoundException {  return forName(className, true, VMStack.getCallingClassLoader());}

查看VMStack的源碼發現 getCallingClassLoader 其實是一個native函數,Android通過底層實現了這個。

//dalvik.system.VMStack/** * Returns the defining class loader of the caller's caller. * * @return the requested class loader, or {@code null} if this is the *     bootstrap class loader. */@FastNativenative public static ClassLoader getCallingClassLoader();

底層想必最終也是拿到LoadedApk里面的ClassLoader。

DexClassLoader

它是一個可以用來加載包含dex文件的jar或者apk文件的,但是它可以用來加載非安裝的apk。比如加載sdcard上面的,或者NetWork的。

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 librarySearchPath 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 librarySearchPath, ClassLoader parent) {    super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);  }}

比如現在很流行的插件化/熱補丁,其實都是通過DexClassLoader來實現的。具體思路是: 創建一個DexClassLoader,通過反射將前者的DexPathList跟系統的PathClassLoader中的DexPathList合并,就可以實現優先加載我們自己的新類,從而替換舊類中的邏輯了。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 翁牛特旗| 瑞丽市| 赤水市| 莱州市| 望都县| 新疆| 吉林市| 西青区| 海口市| 镇沅| 涪陵区| 扎鲁特旗| 佛教| 宣威市| 新余市| 沙湾县| 乐业县| 洪洞县| 麟游县| 天长市| 巴中市| 噶尔县| 马山县| 昂仁县| 丹巴县| 廉江市| 奎屯市| 大兴区| 乌鲁木齐市| 长阳| 克什克腾旗| 沿河| 定安县| 定襄县| 修文县| 三台县| 吉安市| 长顺县| 玛沁县| 苗栗县| 荣昌县|