Android中类加载机制

这篇具有很好参考价值的文章主要介绍了Android中类加载机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android 双亲委派机制

Android 中的双亲委派机制是一种类加载机制,用于从多个类加载器中加载类。它允许类加载器委派加载类的请求给其父类加载器,直到找到可以加载该类的类加载器为止。

工作原理:

当一个类需要被加载时,Java 虚拟机 (JVM) 会首先尝试从当前类加载器加载它。如果当前类加载器无法加载该类,它会将加载请求委派给其父类加载器。这个过程一直持续到根类加载器 (BootStrap ClassLoader),它负责加载 Java 核心库中的类。

如果根类加载器也无法加载该类,则会抛出 ClassNotFoundException 异常。

优点:

**隔离性:**不同的类加载器可以加载不同的类,从而实现类之间的隔离性。
**安全性:**可以控制不同类加载器加载类的权限,从而增强安全性。
**灵活性:**允许在运行时动态加载类,提高了应用程序的灵活性。
示例:

// 自定义类加载器
public class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 从指定路径加载类
        byte[] classData = loadClassData(name);
        return defineClass(name, classData, 0, classData.length);
    }
}

// 使用自定义类加载器加载类
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> myClass = myClassLoader.loadClass("com.example.MyClass");
在上面的示例中,MyClassLoader 是一个自定义类加载器,它从指定路径加载类。当 loadClass("com.example.MyClass") 被调用时,JVM 会使用双亲委派机制尝试从当前类加载器和其父类加载器加载该类。如果无法加载,则会使用 MyClassLoader 加载该类。

注意:

双亲委派机制只适用于类加载,不适用于资源加载。
由于双亲委派机制,子类加载器无法加载父类加载器已经加载的类。
子类加载器到根类加载器的路径是什么样的,有哪些类型的加载器,用法区别
子类加载器到根类加载器的路径:

在 Android 中,类加载器的层次结构如下:

**BootStrap ClassLoader (根类加载器):**加载 Java 核心库中的类。
**Extension ClassLoader:**加载 Java 扩展库中的类。
**System ClassLoader:**加载系统类路径 (CLASSPATH) 中的类。
**自定义类加载器:**加载自定义路径中的类。
子类加载器到根类加载器的路径是:

自定义类加载器 -> System ClassLoader -> Extension ClassLoader -> BootStrap ClassLoader
类型的类加载器:

**BootStrap ClassLoader:**由 Java 虚拟机实现,用于加载 Java 核心库中的类。它是最顶层的类加载器。
**Extension ClassLoader:**加载 Java 扩展库中的类,例如 java.ext.dirs 中的类。
**System ClassLoader:**加载系统类路径 (CLASSPATH) 中的类,例如 java.class.path 中的类。
**自定义类加载器:**由开发者创建,用于加载自定义路径中的类。
用法区别:

**BootStrap ClassLoader:**用于加载 Java 核心库中的类,由 JVM 管理,开发者无法直接使用。
**Extension ClassLoader:**用于加载 Java 扩展库中的类,可以扩展 Java 核心库的功能。
**System ClassLoader:**用于加载系统类路径中的类,是 Android 中最常用的类加载器。
**自定义类加载器:**用于加载自定义路径中的类,可以实现类的隔离、安全控制和动态加载等功能。
示例:

// 自定义类加载器
public class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 从指定路径加载类
        byte[] classData = loadClassData(name);
        return defineClass(name, classData, 0, classData.length);
    }
}

// 使用自定义类加载器加载类
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> myClass = myClassLoader.loadClass("com.example.MyClass");
在上面的示例中,MyClassLoader 是一个自定义类加载器,它从指定路径加载类。

PathClassLoader,DexClassLoader是什么类型加载器,和以上加载器类型怎么对应?


PathClassLoader 和 DexClassLoader 都是 自定义类加载器,用于加载自定义路径中的类。它们与上述类加载器类型的对应关系如下:

类加载器类型    PathClassLoader    DexClassLoader
BootStrap ClassLoader    否    否
Extension ClassLoader    否    否
System ClassLoader    否    否
自定义类加载器    是    是
PathClassLoader 用于加载从文件系统路径加载的类,例如 JAR 文件或目录。它使用 Java 反射 API 来加载类。

DexClassLoader 用于加载从 DEX 文件加载的类。DEX 文件是 Android 应用中使用的可执行文件格式。它使用 Android 框架提供的 dalvik.system.DexClassLoader 类来加载类。

示例:

// PathClassLoader
PathClassLoader pathClassLoader = new PathClassLoader("/path/to/classes.jar", ClassLoader.getSystemClassLoader());
Class<?> myClass = pathClassLoader.loadClass("com.example.MyClass");

// DexClassLoader
DexClassLoader dexClassLoader = new DexClassLoader("/path/to/classes.dex", "/path/to/cache", null, ClassLoader.getSystemClassLoader());
Class<?> myClass = dexClassLoader.loadClass("com.example.MyClass");
在上面的示例中,PathClassLoader 从文件系统路径加载类,而 DexClassLoader 从 DEX 文件加载类。

用法区别:

**PathClassLoader:**用于加载从文件系统路径加载的类,例如 JAR 文件或目录。
**DexClassLoader:**用于加载从 DEX 文件加载的类,通常用于加载 Android 应用中的类。
注意:

PathClassLoader 和 DexClassLoader 都是自定义类加载器,可以实现类的隔离、安全控制和动态加载等功能。
PathClassLoader 和 DexClassLoader 都需要指定父类加载器,通常是 ClassLoader.getSystemClassLoader()。


怎么使用DexClassLoader实现热修复?
使用 DexClassLoader 实现热修复的步骤:

创建 DexClassLoader 实例:

创建一个 DexClassLoader 实例,指定 DEX 文件路径、优化后的 DEX 文件输出路径和父类加载器。
父类加载器通常是 ClassLoader.getSystemClassLoader()。
加载修复类:

使用 DexClassLoader 加载修复类。
修复类通常位于 DEX 文件中。
替换原有类:

使用 Java 反射 API 替换原有类。
找到原有类的 Class 对象,然后使用 set() 方法替换它的父类加载器。
触发类加载:

触发类加载,例如调用修复类的静态方法或创建修复类的实例。
这将导致修复类被加载到内存中。
示例代码:

// 创建 DexClassLoader 实例
DexClassLoader dexClassLoader = new DexClassLoader("/path/to/classes.dex", "/path/to/optimized/dex", null, ClassLoader.getSystemClassLoader());

// 加载修复类
Class<?> fixClass = dexClassLoader.loadClass("com.example.FixClass");

// 替换原有类
Class<?> originalClass = Class.forName("com.example.OriginalClass");
Field parentField = ClassLoader.class.getDeclaredField("parent");
parentField.setAccessible(true);
parentField.set(originalClass.getClassLoader(), dexClassLoader);

// 触发类加载
fixClass.getMethod("fix").invoke(null);
注意:

使用 DexClassLoader 实现热修复需要谨慎,因为它可能会导致类加载冲突和不稳定性。
确保修复类与原有类具有相同的签名和方法实现。
在生产环境中使用热修复之前,应进行充分的测试和验证。
优点:

**快速修复:**DexClassLoader 可以快速加载和替换修复类,实现快速修复。
**隔离性:**修复类与原有类隔离,不会影响原有类的功能。
缺点:

**类加载冲突:**如果修复类与原有类具有相同的类名,可能会导致类加载冲突。
**不稳定性:**热修复可能会导致应用程序不稳定,例如崩溃或异常行为。
**安全风险:**如果修复类包含恶意代码,可能会对应用程序造成安全风险。


如果存在相同的类名,加载顺序是怎样的?
如果使用 DexClassLoader 加载两个具有相同类名的类,加载顺序取决于以下因素:

**父类加载器:**DexClassLoader 实例的父类加载器。
**DEX 文件加载顺序:**DEX 文件的加载顺序。
加载顺序规则:

**优先加载父类加载器中的类:**如果父类加载器中存在与 DEX 文件中类名相同的类,则优先加载父类加载器中的类。
**按 DEX 文件加载顺序加载:**如果父类加载器中不存在该类,则按 DEX 文件加载顺序加载 DEX 文件中的类。第一个加载的 DEX 文件中的类将被加载。
示例:

假设我们有两个 DEX 文件:dex1.dex 和 dex2.dex,其中都包含一个名为 com.example.MyClass 的类。

如果 dex1.dex 先于 dex2.dex 加载,则 dex1.dex 中的 com.example.MyClass 类将被加载。
如果 dex2.dex 先于 dex1.dex 加载,则 dex2.dex 中的 com.example.MyClass 类将被加载。
注意:

如果两个 DEX 文件中包含具有相同类名的类,并且父类加载器中不存在该类,则加载顺序是不可预测的。
为了避免类加载冲突,建议在不同的 DEX 文件中使用不同的类名。
解决类加载冲突:

如果需要在不同的 DEX 文件中加载具有相同类名的类,可以采用以下方法解决类加载冲突:

**使用不同的类名:**为每个类使用不同的类名。
**使用自定义类加载器:**创建自定义类加载器,并控制类加载顺序和类加载行为。
**使用 Java 模块系统:**使用 Java 模块系统将类组织到模块中,并控制模块之间的依赖关系文章来源地址https://www.toymoban.com/news/detail-838848.html

到了这里,关于Android中类加载机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android开发-应用中英文(语言)切换(二)

            APP中针对不同国家不同地区的人群使用那么应用的语言自然也要能够随时进行切换,最近做的项目有中文和英文切换的需求,所以在了解了一下网上常用的方法后记录一下我使用的方法,只是简单的应用,后续如果有不同需求需要自己去改。♻          新建工程就

    2024年02月09日
    浏览(34)
  • Android开发:kotlin语言实现简易计算器

    输入两个数字,可选加减乘除操作符,并计算显示对应结果 随系统切换语言 可对结果进行四舍五入操作 界面布局:activity_main.xml文件代码 字符定义:string.xml文件代码 逻辑实现:MainActivity.kt 文件代码 方法一(偷懒): 复制文件到对应位置 方法二: 1. 绘制界面 2. 编写逻辑

    2023年04月08日
    浏览(33)
  • JVM中类加载的过程

    把.class文件加载到内存中,得到类对象的过程。 找到.class文件,读取文件内容 验证找到的文件是否为一个.class文件,.class文件有明确的数据格式 给类对象分配空间。 注意这个空间是未初始化的空间,内存空间中的数据是全0的。 字符串常量池中的符号引用替换为直接引用。

    2024年02月16日
    浏览(26)
  • Android 安卓开发语言kotlin与Java该如何选择

            如今在Android开发中,应用层开发语言主要是Java和Kotlin,Kotlin是后来加入的,主导的语言还是Java。kotlin的加入仿佛让会kotlin语言的开发者更屌一些,其实不然。         有人说kotlin的引入是解决开发者复杂的逻辑,并且对空指针控制的比较友好,但是我们在开

    2024年02月11日
    浏览(33)
  • 使用Python开发Android软件

    Kivy 是一个开源的 Python 框架(2011年),用于快速开发应用,实现各种当前流行的用户界面,比如多点 触摸等等。 Kivy 可以运行于 Windows, Linux, MacOS, Android, iOS 等当前绝大部分主流桌面/移 动端操作系统。 Kivy 基于 Python,界面UI文件和程序文件相互分离的设计思路,设计简洁

    2024年02月06日
    浏览(28)
  • 自己开发一种编程语言,可以同时开发鸿蒙,Android ios的三个平台的应用

    要开发一种可以在鸿蒙操作系统、Android操作系统和iOS操作系统上运行的编程语言,需要考虑以下几个方面: 语言设计:首先需要设计一种语言,该语言应具备跨平台的特性,能够在不同操作系统上编写应用程序。这需要考虑语法、语义、类型系统等方面的设计。 编译器或解

    2024年02月04日
    浏览(36)
  • Android 优化广告图加载

    作用是:下载完成后,把图片显示在你广告图上,由于glide有三级缓存机制,因此,最好是提前在接口返回的时候,进行预加载,然后进入到广告启动的流程中的时候就可以直接复用上一次的bitmap,不会浪费相应的时间。因此思路如下: 接口数据---开始预加载广告图---》loa

    2024年01月20日
    浏览(35)
  • Android墓碑机制(AndroidU)

        Android为了加速进程的启动速度,在进程退出前台之后并不会立刻杀死进程,而是会尽可能的保留进程,当用户下次启动进程时,进程就会由冷启动变成温启动,启动速度大大加快。但后台进程过多时,会抢占CPU、memory等有限的系统资源,那么如果保证在不杀死进程的情况

    2024年04月26日
    浏览(25)
  • Android Overlay机制

    Android Overlay 是一种资源替换机制,它能在不重新打包 apk 的情况下,覆盖替换 res/ 下的字符和图片等资源。 分为 静态Overlay (Static Resource Overlay) 和 运行时 Overlay (Runtime Resource Overlay) 。 两种 Overlay 方式,都需要资源 id 对应上。大白话就是要替换的资源名称一样、字符串的 id

    2024年02月02日
    浏览(26)
  • 浅析Android OTA机制

    OTA 全称 Over-the-Air Technology,这种在线升级,无需刷机升级的方式,叫做OTA升级,OTA升级可以借助Wifi无线网络或者手机移动网络完成升级,相当于借助空中无线网络完成升级; 项目中需要OTA的功能,因此有了此文,参考下Android的OTA实现机制,可以看到Android的OTA机制随着版本

    2024年01月25日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包