欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Android類加載ClassLoader

 更新時間:2017年04月26日 08:33:05   作者:yourbay.me  
本篇文章主要介紹了詳解Android類加載ClassLoader,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

基本知識

Java的類加載設(shè)計了一套雙親代理的模式,使得用戶沒法替換系統(tǒng)的核心類,從而讓應(yīng)用更安全。所謂雙親代理就是指,當(dāng)加載類的時候首先去Bootstrap中加載類,如果沒有則去Extension中加載,如果再沒有才去AppClassLoader中去加載。從而實現(xiàn)安全和穩(wěn)定。

Java ClassLoader

BootstrapClassLoader

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

比如: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

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

自定義ClassLoader

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

ClassLoader中與加載類相關(guān)的方法:

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

也許你不太了解上面幾個函數(shù)的區(qū)別,沒關(guān)系,我們來看下源碼是如何實現(xiàn)的。

//ClassLoader.java
protected 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;
}

所以優(yōu)先級大概如下:

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

Android ClassLoader

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

我們只討論PathClassLoader和DexClassLoader

PathClassLoader

用來加載安裝了的應(yīng)用中的dex文件。它也是Android里面的一個最核心的ClassLoader了。相當(dāng)于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);
  }
}

它的實例化是通過調(diào)用 ApplicationLoaders.getClassLoader 來實現(xiàn)的。

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

那么問題來了,當(dāng)Android加載class的時候,LoadedApk中的ClassLoader是怎么被調(diào)用到的呢?

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

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

查看VMStack的源碼發(fā)現(xiàn) getCallingClassLoader 其實是一個native函數(shù),Android通過底層實現(xiàn)了這個。

//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.
 */
@FastNative
native 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);
  }
}

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論