首页 > 其他分享 >类加载器与双亲委派机制

类加载器与双亲委派机制

时间:2024-11-02 18:45:34浏览次数:4  
标签:委派 String parent ClassLoader 双亲 Android PathClassLoader 加载

类加载器

  在Java虚拟机(JVM)中,类加载器(Class Loader)是负责将字节码文件加载到内存中并转换为类对象的组件。类加载器的主要任务是将 .class 文件加载到 JVM 中,以便程序能够使用这些类。JVM中的类加载器机制是Java平台的关键部分,它实现了Java的动态类加载特性。

JVM的类加载器

  • Bootstrap ClassLoader(引导类加载器)
      这是最基础的类加载器,由JVM自身实现,负责加载JRE核心库中的类(例如 java.lang.、java.util. 等)。引导类加载器直接使用本地代码来实现,它不会继承自 java.lang.ClassLoader 类。引导类加载器负责加载/lib目录下的类。

  • Extensions ClassLoader(扩展类加载器)
      Java中的实现类为ExtClassLoader,负责加载Java扩展库中的类,通常位于 JAVA_HOME/lib/ext 目录下。它是由 java.lang.ClassLoader 类的子类实现的。扩展类加载器用于加载一些标准扩展的类库,如加密、图形处理等功能扩展包。

  • Application ClassLoader(应用程序类加载器)
      Java中的实现类为AppClassLoader,是与我们接触最多的类加载器,开发人员写的代码默认由它来加载,ClassLoader.getSystemClassLoader返回的就是它。也称为系统类加载器,负责加载应用程序的类路径(classpath)下的类,包括我们编写的自定义类以及第三方库。它通常是类加载层次结构中最高级别的加载器,大多数应用程序的类加载都通过该加载器来完成。

类加载器的工作机制

Java中类的加载过程分为三个阶段:加载、连接 和 初始化。

  • 加载:通过类的全限定名查找字节码文件,并将其加载到内存中,生成 java.lang.Class 对象。
  • 连接:将类文件中的符号引用解析为直接引用,并进行类的验证、准备和解析等过程。
  • 初始化:为类的静态变量赋值,并执行静态初始化块(static 块)。

双亲委派机制

  类加载器采用了双亲委派模型,即一个类加载器在加载类时,会首先委托其父加载器来加载,只有当父加载器无法找到该类时,才会尝试自己加载。这一机制确保了Java核心类库的安全性和一致性,避免了类的重复加载。

  • Bootstrap ClassLoader 没有父加载器,它会直接加载核心类库;
  • Extension ClassLoader 将委托给 Bootstrap ClassLoader;
  • Application ClassLoader 将委托给 Extension ClassLoader。

Android中的类加载器

  在Android中,类加载器的工作方式与Java标准中的类加载机制类似,但为了适应移动环境的特殊需求,Android对类加载器进行了优化和扩展。Android的类加载器主要用于加载 .dex 文件(Dalvik/ART Executable)而非标准的 .class 文件,这些 .dex 文件是经过优化的,适用于Android的Dalvik虚拟机和ART运行时环境。

  • BootClassLoader(引导类加载器)
      和Java中的Bootstrap ClassLoader类似,负责加载Android核心框架和库文件中的类,如Java标准库和Android基础框架的类。由系统提供,确保这些类优先加载。BootClassLoader 是内置的,不暴露给开发者,也无法直接访问。

  • PathClassLoader(路径类加载器)
      PathClassLoader 用于加载应用程序的代码和资源,即开发者自己的代码和依赖库(如 .dex 文件和 .apk 文件)。其加载路径是应用的安装路径和 libs 目录,通常用于加载应用的主类和标准库,不支持加载外部的 .jar 文件。
      PathClassLoader 可以在应用的 ClassLoader 层次结构中被直接访问,并通过 getClassLoader() 方法获取。

  • DexClassLoader
      DexClassLoader 是Android特有的类加载器,允许在运行时加载动态 .dex 文件或 .jar 文件。这在Java标准中没有对应的类加载器。可以加载存储在外部存储中的 .dex 或 .jar 文件,常用于插件化开发和动态加载第三方库。DexClassLoader 可以灵活加载动态 .dex 文件,这在应用需要动态更新或加载新功能模块时非常实用。

Android中的双亲委派

  Android的类加载器仍然采用双亲委派模型,确保系统类优先加载,避免与应用类发生冲突。这意味着 BootClassLoader 会先加载系统库和框架类,只有当上层类加载器无法加载某个类时,才会尝试由应用的 PathClassLoaderDexClassLoader 来加载。
  Android将 .class 文件转化为 .dex 文件,以优化内存使用和执行效率。 .dex 文件可以包含多个类,并且经过压缩和优化,便于在移动设备上的高效加载。Android的 DexClassLoaderPathClassLoader 都能将 .dex 文件加载到内存中。

Android中查看特定类的类加载器信息

  新建一个Native C++项目,在onCreate方法里添加代码

        ClassLoader thisclassloader = MainActivity.class.getClassLoader();
        ClassLoader stringclassloader = String.class.getClassLoader();
        Log.d("classloader","MainActivity is in "+thisclassloader.toString());
        Log.d("classloader","String is in "+stringclassloader.toString());

在这里插入图片描述
可以看到打印出来的一些信息

MainActivity is in dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.classloader01-Kjp6QH8dtZClZJTtM2hgBg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.classloader01-Kjp6QH8dtZClZJTtM2hgBg==/lib/arm64, /data/app/com.example.classloader01-Kjp6QH8dtZClZJTtM2hgBg==/base.apk!/lib/arm64-v8a, /system/lib64]]]

String is in java.lang.BootClassLoader@16fc266

  MainActivityPathClassLoader 加载,这是Android应用中常见的类加载器,主要用于加载应用的 .dex 文件和库。PathClassLoader 的描述中包含了zip file 路径:这是 base.apk 的文件路径,即应用的主要 APK 文件;nativeLibraryDirectories 路径:这是包含本地库(如 .so 文件)的目录,在 64 位设备上包含 /lib/arm64 和 /lib/arm64-v8a,以及系统目录 /system/lib64。
  String 类是由 BootClassLoader 加载的,日志中显示了其为 java.lang.BootClassLoader@16fc266。在Android中,BootClassLoader 是用来加载核心Java类库(如 java.lang.、java.util. 等)。

分析源码

  • ClassLoader
      在源码中找到ClassLoader类,发现它是一个抽象类在这里插入图片描述
  • PathClassLoader
      在源码中查找PathClassLoader类,发现它是在dalvik.system包下的类,继承自BaseDexClassLoader
    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);
        }
    }
    
  • BaseDexClassLoader
    去源码中找BaseDexClassLoader类,发现它也是在dalvik.system包下的类,继承自ClassLoader
    在这里插入图片描述
  • parent属性
    parent属性是ClassLoader类的属性,它的类型是ClassLoader,它就是父加载器了
    在这里插入图片描述
  • getParent()方法
    getParent方法是ClassLoader类的类方法,用于获取当前类加载器的父类加载器。
    在这里插入图片描述

写一个函数用来打印父加载器

    public static void printClassLoader(ClassLoader classLoader){
        Log.e("printClassLoader ","this->"+classLoader.toString());
        ClassLoader parent = classLoader.getParent();
        if (parent==null){
            Log.e("printClassLoader","parent is null");
        } else {
            while (parent!=null){
                Log.e("printparentClassLoader ","parent->"+parent.toString());
                parent=parent.getParent();
                if (parent==null){
                    Log.e("printClassLoader","parent is null");
                }
            }
        }
    }
  • MainActivity类的ClassLoader作为参数传进去
    printClassLoader(thisclassloader);在这里插入图片描述
    根据下面结果可以知道PathClassLoader的父加载器是BootClassLoaderBootClassLoader的父类加载器是null

    this->dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.classloadertest-epsw2WZfB2ncDxfrINyUmg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.classloadertest-epsw2WZfB2ncDxfrINyUmg==/lib/arm64, /data/app/com.example.classloadertest-epsw2WZfB2ncDxfrINyUmg==/base.apk!/lib/arm64-v8a, /system/lib64]]]
    parent->java.lang.BootClassLoader@84d413c
    parent is null
    
  • String类的ClassLoader作为参数传进去
    printClassLoader(stringclassloader);
    在这里插入图片描述
    BootClassLoader的父类加载器是null

使用类加载器加载类

  • 使用thisclassloader加载MainActivity

            try {
                Class MainActivityClass = thisclassloader.loadClass("com.example.classloadertest.MainActivity");
                Log.e("classloadertest","load MainActivity success"+MainActivityClass.toString());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
    

    thisclassloaderPathClassLoader加载器,它可以加载MainActivity
    在这里插入图片描述

  • 使用stringclassloader加载MainActivity

            try {
                Class MainActivityClass = stringclassloader.loadClass("com.example.classloadertest.MainActivity");
                Log.e("classloadertest","load MainActivity success!"+MainActivityClass.toString());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
    

    stringclassloaderBootClassLoader加载器,无法加载MainActivity,会触发异常
    在这里插入图片描述

  • 使用thisclassloader加载String

            try {
                Class StringClass = thisclassloader.loadClass("java.lang.String");
                Log.e("classloadertest","load java.lang.String success!"+StringClass.toString());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
    

    thisclassloaderPathClassLoader加载器,它的父加载器是BootClassLoader加载器,可以加载String类 。在这里插入图片描述

  • 使用stringclassloader加载String

            try {
                Class StringClass = stringclassloader.loadClass("java.lang.String");
                Log.e("classloadertest","load java.lang.String success!"+StringClass.toString());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
    

    stringclassloaderBootClassLoader加载器,可以加载String类。
    在这里插入图片描述

标签:委派,String,parent,ClassLoader,双亲,Android,PathClassLoader,加载
From: https://blog.csdn.net/weixin_74305514/article/details/143437587

相关文章

  • Openlayers高级交互(15/20):显示海量多边形,10ms加载完成
    本示例演示在vue+openlayers项目中通过WebGLVectorLayerRenderer方式加载海量多边形数据。这里相当于将海量的数据放在同一个层的source中,然后通过webglTile的方式渲染出这一层。本示例数据为5000个多边形,加载速度超级快。一、示例效果专栏名称内容介绍Openlay......
  • 什么是ETL(提取、转换、加载)过程在数据处理中的重要性
    ETL(提取、转换、加载)过程在数据处理中承担着至关重要的职责,它直接决定了数据分析的质量和效率。ETL过程包括三个主要步骤:提取(Extract)、转换(Transform)和加载(Load),是企业数据仓库(DW)建设和维护的核心。提取步骤负责从多个数据源收集信息、转换步骤将原始数据清洗并转换为统一格式以便......
  • 《保卫萝卜》客户端缺失pthreadvce2.dll 文件?详解《保卫萝卜》Luobo.exe 加载 pthread
    在享受《保卫萝卜》这款趣味横生的塔防游戏时,部分玩家可能会遇到游戏无法启动的问题,屏幕上弹出错误提示:“由于找不到pthreadvce2.dll,无法继续执行代码。”这一错误通常意味着你的电脑系统中缺失了pthreadvce2.dll这个关键的动态链接库(DLL)文件。别担心,本文将为你提供详细的修......
  • PostgreSQL技术大讲堂 - 第70讲:PG数据库数据加载调优案例
     PostgreSQL技术大讲堂-第70讲,主题:postgresq数据库数据加载调优案例讲课内容:  1、数据库参数调整  2、后台进程cpu绑定调整  3、数据库并行操作调整  数据加载是每个DBA经常需要完成的工作,如何让数据加载变得更快,本期视频跟大家一起分享调优带来的乐趣......
  • Qt5.9使用QWebEngineView加载网页速度慢 ,卡顿,原因是默认开启了代理
     Qt5.9使用QWebEngineView加载网页速度慢,卡顿,原因是默认开启了代理https://blog.csdn.net/zhanglixin999/article/details/131161944 BUG单下的留言讲明了问题发生的原因,那就是系统默认设置为自动寻找代理,而使用代理后延迟会变得非常大。(1)关闭自动代理接的pro文件内添......
  • GEE教程:JRC water 1.4数据的直方图频率统计和图表加载
    目录简介函数ui.Chart.image.histogram(image, region, scale, maxBuckets, minBucketWidth, maxRaw, maxPixels)Arguments:Returns: ui.ChartsetOptions(options)Arguments:Returns: ui.Chartee.Reducer.histogram(maxBuckets, minBucketWidth, maxRaw)Ar......
  • Laravel无法加载.env的问题
    在万网虚拟主机上,发现laravel无法加载.env中配置的信息,然后一路跟踪发现,问题出在PHPDotEnv这个库上在Loader.php里有一个函数如下:publicfunctionsetEnvironmentVariable($name,$value=null){list($name,$value)=$this->normaliseEnvironmentVariable($name,$value......
  • 告别龟速加载:三种压缩算法让你的网站瞬间提速!
    三种压缩算法,让你的网站飞起来!!!2万字深度长文,让你一次看个爽!!!欢迎订阅专栏,永不收费,hacker精神,更快获得第一手优质博文!!!前言在当今快节奏的互联网世界,用户对网站加载速度的要求越来越高。一个加载缓慢的网站不仅会损害用户体验,还会影响搜索引擎排名,最终导致流量和转......
  • Vue组件的动态加载和卸载
            组件的动态注册还是比较容易的,使用<component:is="组件id"></component>即可,但动态卸载有难度,相关文献较少。不过,如果巧妙使用vnode,就能轻松实现!       下图展示了4个代表不同文档材料的Vue组件。为简化起见,每个组件用一个DIV元素表示,其内容为一张图......
  • 在使用asm包进行动态类加载的时候的打包问题
     如图所示,开发时使用的jdk包下面的asm包,在进行打包时提示asm包不存在,打包方式使用如下: 目前提供两种解决方案:1:修改打包方式,将jdk的包也打进去:<plugin><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><t......