ClassLoader&雙親委派模型

類加載器的作用:

  • 類加載,通過(guò)類的權(quán)限定名獲取此類的二進(jìn)制字節(jié)流
  • 確定被加載的類在jvm中的唯一性

兩個(gè)類是否相等的依據(jù):是否由同一個(gè)ClassLoader加載

兩個(gè)類是否相等的判斷:

  • equals
  • isAssignableFrom
  • isInstance
類加載器的類型:
  1. 啟動(dòng)類加載器(Bootstrap ClassLoader)
  • 用于加載存放在<JAVA_HOME>\lib目錄下和被-Xbootclasspath參數(shù)指定的類(事先定義好的類)
  • 僅按文件名識(shí)別,如:rt.jar,名字不符合的類庫(kù)即使放在lib目錄中也不會(huì)被加載
  • 無(wú)法被java程序直接使用
  1. 擴(kuò)展類加載器(Extension ClassLoader)
  • 加載JAVA_HOME>\lib\ext目錄中和被java.ext.dirs系統(tǒng)變量所指定的路徑中的類
  • 開發(fā)者可以直接使用擴(kuò)展類加載器
  1. 應(yīng)用程序類加載器
  • 負(fù)責(zé)加載 用戶類路徑(ClassPath)上所指定的類庫(kù)
  • 該類加載器是ClassLoader中的getSystemClassLoader()方法的返回值

雙親委派模型

雙親委派模型

注意點(diǎn):

  • 除了頂層的啟動(dòng)類加載器,所有的加載器都有父類加載器
  • 加載器之前的關(guān)系是組合關(guān)系來(lái)復(fù)用父類加載器的代碼,不是繼承
雙親委派模型的工作流程代碼實(shí)現(xiàn)在java.lang.ClassLoader的loadClass()
protected Class<?> loadClass(String name, boolean resolve) 
        throws ClassNotFoundException { 
    Class<?> c = findLoadedClass(name); 

  // 檢查需要加載的類是否已經(jīng)被加載過(guò)
    if (c == null) { 
        try { 
             // 若沒(méi)有加載,則調(diào)用父加載器的loadClass()方法
            if (parent != null) { 
                c = parent.loadClass(name, false); 
            }else{ 
                // 若父類加載器為空,則默認(rèn)使用啟動(dòng)類加載器作為父加載器
                c=findBootstrapClassOrNull(name); 
            } 
        } catch (ClassNotFoundException e) { 
            // 若父類加載器加載失敗會(huì)拋出ClassNotFoundException, 
            //說(shuō)明父類加載器無(wú)法完成加載請(qǐng)求 
        } 
        if(c==null){ 
            // 在父類加載器無(wú)法加載時(shí) 
            // 再調(diào)用本身的findClass方法進(jìn)行類加載 
            c=findClass(name); 
        } 
    } 
    if(resolve){ 
        resolveClass(c); 
    } 
    return c; 
}
加載流程:
  1. 當(dāng)一個(gè)加載器收到加載請(qǐng)求需求時(shí),會(huì)提交給他的父類加載器去完成
  2. 只有當(dāng)父類加載器反饋無(wú)法加載時(shí),自己才會(huì)去加載
優(yōu)點(diǎn):

類加載器的層級(jí)關(guān)系保證了java類的帶優(yōu)先級(jí)的層次關(guān)系:

  • Object類只有啟動(dòng)類加載器會(huì)加載,所以只會(huì)有一個(gè)Object類,如果沒(méi)有雙親委派模型,多個(gè)類加載加載Object類會(huì)出現(xiàn)多個(gè)Object類,無(wú)法保證java的最基礎(chǔ)行為;

安卓的類加載器

  • BootClassLoader:加載framework中的類,如Activity.class
  • PathClassLoader:加載項(xiàng)目中的類,如MainActivity.class,其父加載器是BootClassLoader
  • DexClassLoader:加載指定目錄的類,其父加載器也是BootClassLoader
  • InMemoryClassLoader:加載內(nèi)存中的類,不如字節(jié)數(shù)組(類似動(dòng)態(tài)代理中的那個(gè)東西)

類加載器加載類的原理:

BaseDexClassLoader:
  private final DexPathList pathList;

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
...
        Class c = pathList.findClass(name, suppressedExceptions);
...
    }
DexPathList:
    private Element[] dexElements;

    public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        return null;
    }

    private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
            List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
      Element[] elements = new Element[files.size()];
      int elementsPos = 0;
      /*
       * Open all files and load the (direct or contained) dex files up front.
       */
      for (File file : files) {
          if (file.isDirectory()) {
              // We support directories for looking up resources. Looking up resources in
              // directories is useful for running libcore tests.
              elements[elementsPos++] = new Element(file);
          } else if (file.isFile()) {
              String name = file.getName();

              DexFile dex = null;
              if (name.endsWith(DEX_SUFFIX)) {
                  // Raw dex file (not inside a zip/jar).
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                      if (dex != null) {
                          elements[elementsPos++] = new Element(dex, null);
                      }
                  } catch (IOException suppressed) {
                      System.logE("Unable to load dex file: " + file, suppressed);
                      suppressedExceptions.add(suppressed);
                  }
              } else {
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                  } catch (IOException suppressed) {
                      /*
                       * IOException might get thrown "legitimately" by the DexFile constructor if
                       * the zip file turns out to be resource-only (that is, no classes.dex file
                       * in it).
                       * Let dex == null and hang on to the exception to add to the tea-leaves for
                       * when findClass returns null.
                       */
                      suppressedExceptions.add(suppressed);
                  }

                  if (dex == null) {
                      elements[elementsPos++] = new Element(file);
                  } else {
                      elements[elementsPos++] = new Element(dex, file);
                  }
              }
              if (dex != null && isTrusted) {
                dex.setTrusted();
              }
          } else {
              System.logW("ClassLoader referenced unknown path: " + file);
          }
      }
      if (elementsPos != elements.length) {
          elements = Arrays.copyOf(elements, elementsPos);
      }
      return elements;
    }

    private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
                                       Element[] elements)
            throws IOException {
        if (optimizedDirectory == null) {
            return new DexFile(file, loader, elements);
        } else {
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
        }
    }

Element: DexPathList的一個(gè)靜態(tài)內(nèi)部類
       private final DexFile dexFile;

        public Class<?> findClass(String name, ClassLoader definingContext,
                List<Throwable> suppressed) {
            return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
                    : null;
        }

dexFile.loadClassBinaryName()是一個(gè)native方法


https://blog.csdn.net/qq_22393017/article/details/81811101

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 己亥年最后一次去曲江醫(yī)院。。。。。。 是的,從去年過(guò)完年后開始,每月一次,到最后一個(gè)月的每周一次,超預(yù)產(chǎn)期...
    面朝太陽(yáng)的揚(yáng)揚(yáng)閱讀 119評(píng)論 0 0
  • 最近看到李子柒火到國(guó)外的新聞,突然萌生了一個(gè)網(wǎng)紅夢(mèng)。 如果有一天在公司混不下去了, 那我也去做短視頻,我就去種種菜...
    布令閱讀 202評(píng)論 0 0
  • 你可知道我 為了這一天 前五百年 我安撫了多少個(gè)孤獨(dú)的魂靈 我沒(méi)有屬于自己的五官 相由心生的含義 就是隨那些靈魂 ...
    我不是石頭我很熱情閱讀 182評(píng)論 0 0
  • 好久好久,沒(méi)怎么寫東西,就把從GitHub上淘來(lái)的各種各樣語(yǔ)言的爬蟲框架分享給大家。 Python python自...
    淺淺的笑意閱讀 8,945評(píng)論 1 15

友情鏈接更多精彩內(nèi)容