自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

了解 Android 類加載器的工作原理,DexPathList 在類加載過程中的作用

移動(dòng)開發(fā)
Android的類加載器系統(tǒng)基于JVM的類加載器模型,但有一些特定的調(diào)整和優(yōu)化,以適應(yīng)Android平臺(tái)的需要。

類加載器

在Android中,類加載器(ClassLoader)是一個(gè)重要的組件,負(fù)責(zé)在運(yùn)行時(shí)動(dòng)態(tài)加載JVM和Android類庫。Android的類加載器系統(tǒng)基于JVM的類加載器模型,但有一些特定的調(diào)整和優(yōu)化,以適應(yīng)Android平臺(tái)的需要。

(1) Bootstrap ClassLoader:

  • 這是最頂層的類加載器,由JVM實(shí)現(xiàn)。
  • 主要加載Java和Android核心類庫。
  • 通常通過null作為父加載器。

(2) PathClassLoader(或DexClassLoader):

  • Android特有的類加載器,用于從APK文件、DEX文件或JAR/ZIP文件中加載類。
  • PathClassLoader是Android應(yīng)用默認(rèn)的類加載器,用于加載應(yīng)用的類和資源。

DexClassLoader是PathClassLoader的一個(gè)子類,提供了從指定的路徑加載DEX文件的能力,動(dòng)態(tài)加載插件或模塊化場(chǎng)景常用加載器。

//DexClassLoader.java
package dalvik.system;

public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
    
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(dexPath, null, librarySearchPath, parent);
    }
}

//PathClassLoader
package dalvik.system;

public class PathClassLoader extends BaseDexClassLoader {

   public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }
    
    public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
        super(dexPath, null, librarySearchPath, parent);
    }
}

可以發(fā)現(xiàn)PathClassLoader和DexClassLoader源碼很簡(jiǎn)單,只包含了一個(gè)構(gòu)造函數(shù),去調(diào)用父類BaseDexClassLoader(所有的工作都應(yīng)該是在BaseDexClassLoader里完成的了)。而這兩個(gè)加載器不同的是PathClassLoader的構(gòu)造中少了optimizedDirectory這個(gè)參數(shù),原因是PathClassLoader是加載/data/app中的apk,也就是系統(tǒng)中的apk,而這部分的apk都會(huì)解壓釋放dex到指定的目錄中,這個(gè)操作由系統(tǒng)完成,不需要單獨(dú)傳入路徑,而DexClassLoader傳入,用來緩存需要加載的dex文件,并創(chuàng)建一個(gè)DexFile對(duì)象,如果為null,會(huì)直接使用dex文件原有路徑創(chuàng)建DexFile(這個(gè)參數(shù)已經(jīng)棄用,自API26起無效)。

(3) System ClassLoader(或AppClassLoader):

  • Android系統(tǒng)的應(yīng)用類加載器,繼承自URLClassLoader。
  • 用于加載Android系統(tǒng)的類和應(yīng)用的類。
  • 在Android中不直接引用System ClassLoader或AppClassLoader,通過ClassLoader.getSystemClassLoader()獲取。

(4) 自定義ClassLoader:

  • 可以繼承ClassLoader類或其子類(如DexClassLoader)來創(chuàng)建自定義的類加載器。
  • 自定義類加載器可以用于加載網(wǎng)絡(luò)上的類、從數(shù)據(jù)庫加載加密的類、或者實(shí)現(xiàn)更復(fù)雜的類加載邏輯。

類加載器的主要用途:

  • 動(dòng)態(tài)加載和執(zhí)行代碼,如插件化開發(fā)、熱更新等。
  • 加載和執(zhí)行不同來源的代碼,如從網(wǎng)絡(luò)下載的JAR包或DEX文件。
  • 隔離不同來源的代碼,防止類沖突和安全問題。

注意:濫用類加載器可能導(dǎo)致內(nèi)存泄漏和性能問題。在使用類加載器時(shí),應(yīng)該仔細(xì)考慮其生命周期和資源管理。

DexPathList

DexPathList是DexClassLoader和BaseDexClassLoader等類加載器用于處理DEX文件路徑的一個(gè)內(nèi)部類。當(dāng)使用DexClassLoader或BaseDexClassLoader加載DEX文件時(shí),DexPathList起到了關(guān)鍵的作用。

(1) 作用:DexPathList負(fù)責(zé)管理和維護(hù)DEX文件的路徑信息,使類加載器能夠正確地找到并加載DEX文件中的類。

(2) 構(gòu)造:DexPathList在DexClassLoader或BaseDexClassLoader的構(gòu)造函數(shù)中被創(chuàng)建。構(gòu)造DexPathList時(shí),需要提供DEX文件的路徑、優(yōu)化目錄、庫路徑以及父類加載器等參數(shù)。

public class BaseDexClassLoader extends ClassLoader {

    private final DexPathList pathList;
    
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);
    }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }
}

(3) 成員變量:DexPathList有一個(gè)私有的final成員變量dexElements,是一個(gè)Element數(shù)組,包含了所有DEX文件的Element對(duì)象,每個(gè)Element對(duì)象對(duì)應(yīng)一個(gè)DEX文件。

private final Element[] dexElements;

public DexPathList(ClassLoader definingContext, String dexPath,
        String libraryPath, File optimizedDirectory) {
    ...
    this.definingContext = definingContext;
    this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,suppressedExceptions);
    ...
}

(4) 加載DEX文件:在DexPathList的構(gòu)造函數(shù)中,會(huì)調(diào)用makeDexElements()方法來加載DEX文件。這個(gè)方法會(huì)遍歷提供的DEX文件路徑列表,并為每個(gè)DEX文件創(chuàng)建一個(gè)Element對(duì)象,然后將這些Element對(duì)象添加到dexElements數(shù)組中。

private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) {
    // 1.創(chuàng)建Element集合
    ArrayList<Element> elements = new ArrayList<Element>();
    // 2.遍歷所有dex文件(也可能是jar、apk或zip文件)
    for (File file : files) {
        ZipFile zip = null;
        DexFile dex = null;
        String name = file.getName();
        ...
        // 如果是dex文件
        if (name.endsWith(DEX_SUFFIX)) {
            dex = loadDexFile(file, optimizedDirectory);

        // 如果是apk、jar、zip文件(這部分在不同的Android版本中,處理方式有細(xì)微差別)
        } else {
            zip = file;
            dex = loadDexFile(file, optimizedDirectory);
        }
        ...
        // 3.將dex文件或壓縮文件包裝成Element對(duì)象,并添加到Element集合中
        if ((zip != null) || (dex != null)) {
            elements.add(new Element(file, false, zip, dex));
        }
    }
    // 4.將Element集合轉(zhuǎn)成Element數(shù)組返回
    return elements.toArray(new Element[elements.size()]);
}

(5) 加載類:當(dāng)類加載器需要加載一個(gè)類時(shí),會(huì)通過DexPathList的loadClass()方法來實(shí)現(xiàn)。這個(gè)方法會(huì)遍歷dexElements數(shù)組中的每個(gè)Element對(duì)象,并嘗試從對(duì)應(yīng)的DEX文件中加載類。一旦找到需要加載的類,就會(huì)返回該類的Class對(duì)象。

public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        // 遍歷出一個(gè)dex文件
        DexFile dex = element.dexFile;

        if (dex != null) {
            // 在dex文件中查找類名與name相同的類
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    if (dexElementsSuppressedExceptions != null) {
        suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
    }
    return null;
}

(6) 優(yōu)化:為了提高性能,DexPathList還支持DEX文件的優(yōu)化。在加載DEX文件時(shí),可以將DEX文件優(yōu)化到指定的目錄中,以減少內(nèi)存占用和提高加載速度。

責(zé)任編輯:趙寧寧 來源: 沐雨花飛蝶
相關(guān)推薦

2012-02-14 13:39:57

Java

2012-02-09 10:31:17

Java

2021-07-05 06:51:43

Java機(jī)制類加載器

2019-12-09 15:08:30

JavaTomcatWeb

2024-03-12 07:44:53

JVM雙親委托機(jī)制類加載器

2024-12-04 09:01:55

引導(dǎo)類加載器C++

2024-03-08 08:26:25

類的加載Class文件Java

2012-11-06 10:19:18

Java自定義加載Java類

2010-03-16 14:58:15

Java類加載器

2021-01-06 09:01:05

javaclass

2023-05-10 11:07:18

2024-12-02 09:01:23

Java虛擬機(jī)內(nèi)存

2024-04-09 08:41:41

JVM類加載Java

2019-07-24 08:34:35

Java對(duì)象數(shù)據(jù)結(jié)構(gòu)

2024-09-06 09:37:45

WebApp類加載器Web 應(yīng)用

2009-08-24 11:36:27

CLR加載過程

2021-07-28 10:08:19

類加載代碼塊面試

2009-02-03 09:42:53

JAVA類JVM指令forName方法

2020-10-26 11:20:04

jvm類加載Java

2020-09-30 08:26:33

Spring Boot
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)