Java和Android中的ClassLoader

一、Java中的类加载器

我们知道.class文件存储着Java程序代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件
并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程称为类加载。

首先我们来了解下Java中的类加载器,Java中的类加载器主要有两种类型

系统类加载和自定义类加载器

1. 系统类加载:
  1. Bootstrap ClassLoader 启动类加载器

    C++语言实现的;是虚拟机自身的一部分,因此它并不继承java.lang.ClassLoader

    加载的是JVM自身需要的类;如java.lang.、java.uti.等这些系统类;

    将/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中

    出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

  2. Extensions ClassLoader 扩展类加载器

    sun.misc.Launcher$ExtClassLoader类,继承与java.lang.ClassLoader类

    用于加载 Java 的拓展类

    拓展类的jar包一般会放在$JAVA_HOME/jre/lib/ext目录下;也可以通过-Djava.ext.dirs选项添加和修改Extensions ClassLoader加载的路径

  3. App ClassLoader

    sun.misc.Launcher$AppClassLoader,继承与java.lang.ClassLoader类

    负责加载当前应用程序Classpath目录下的所有jar和Class文件也可以加载通过-Djava.class.path选项所指定的目录下的jar和Class文件,即所谓的Classpath

2. 自定义类加载器

除了系统提供的类加载器,还可以自定义类加载器,自定义类加载器通过继承java.lang.ClassLoader类的方式来实现自己的类加载器

自定义加载器用于加载网络上的或者某个文件夹中的jar包和Class文件

实现自定义ClassLoader步骤
1. 定义一个自定义ClassLoader并继承ClassLoader
2. 复写findClass方法,并在findClass方法中调用defineClass方法

二、类加载器查找类的过程–双亲委托模式

我们知道ClassLoader都是通过其中的loadClass方法来加载类的,那么我们先看下ClassLoader的loadClass源码

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException{
    //判断是否已经加载,如果已经加载则直接返回
    Class<?> c = findLoadedClass(name);
    if (c == null) {
        try {
            //判断当前加载器是否有父加载器,有的话就调用父加载器的loadClass方法
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                //没有父加载器,调用BootstrapClassLoader进行加载      
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
            // ClassNotFoundException thrown if class not found
            // from the non-null parent class loader
        }
        //如果仍然无法加载成功,则调用自身的findClass进行加载 
        if (c == null) {
            // If still not found, then invoke findClass in order
            // to find the class.
            c = findClass(name);
        }
    }
    return c;
}

在加载器有一个parent父加载器的概念,注意父加载是创建加载器的时候指定的,并不是继承关系。在java中

App ClassLoader的父加载器 是Extensions ClassLoader

Extensions ClassLoader的父加载器 是Bootstrap ClassLoader

而Bootstrap ClassLoader是根加载器,没有父加载器了

如果我们自定义一个加载器,父加载器指定为App ClassLoader,那么我们发现类加载的过程就是

  1. 判断当前类是否已经加载,如果已经加载则直接返回,避免重复加载
  2. 如果未加载,则递归遍历调用其父加载器的loadClass方法,父加载器的loadClass方法也是重复1和2这两步,如果加载成功则返回,如果没加载成功,则继续向上遍历,直到没有没有了父加载器,则调用BootstrapClass的loadClass方法
  3. 如果遍历完后还没有加载成功,则调用加载器自己的findClass方法

这就是所谓的双亲委托模式。双亲委托模式主要有两点好处:
1. 避免重复加载,如果已经加载过一次Class,则再次加载的时候会从缓存中读取
2. 更加安全,可以避免自定义一个String类来替代系统的String类这种情况发生。注意的是: 只有两个类名一致并且被同一个类加载器加载的类,Java虚拟机才会认为它们是同一个类

三、Android中的类加载器

我们知道Android中对.class文件进行了合并优化,生成了.class.dex文件,所以在Android中的类加载,其实就是加载.dex文件

在Android中主要定义了两个ClassLoader来进行类加载

即DexClassLoader和PathClassLoader,他们都继承与BaseDexClassLoader,而BaseDexClassLoader又继承与ClassLoader

PathClassLoader和DexClassLoader都继承自BaseDexClassLoader,其中的主要逻辑都是在BaseDexClassLoader完成的

我们下面来看下这三者的构造器的构造函数

BaseDexClassLoader

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
    super(parent);
    this.pathList = new DexPathList(this, dexPath, librarySearchPath, optimizedDirectory);
}

参数详解:
1. dexPath:JAR/APK文件路径的列表,多个的话默认可用“:”分割;可以是APK、DEX和JAR的路径
2. optimizedDirectory:该参指定从jar或者Apk中解压出的dex 文件存放的路径。这也是对apk中dex根据平台进行ODEX优化的过程

APK是一个程序压缩包,里面包含dex文件,ODEX优化就是把包里面的执行程序提取出来,就变成ODEX文件

系统只有第一次启动的时候,会把JAR或者APK解压到 /data/dalvik-cache(针对PathClassLoader)或者optimizedDirectory(针对DexClassLoader)目录,之后也是直接读取目录下的的dex文件
3. librarySearchPath:指目标类中所使用的C/C++库存放的路径
4. parent:父加载器

DexClassLoader

public DexClassLoader(String dexPath, String optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}

DexClassLoader支持加载APK、DEX和JAR,也可以从SD卡进行加载。在BaseDexClassLoader里对”.jar”,”.zip”,”.apk”,”.dex”后缀的文件最后都会生成一个对应的dex文件,所以最终处理的还是dex文件,生成的dex文件就放在optimizedDirectory目录下

PathClassLoader

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

可以看出PathClassLoader将optimizedDirectory置为Null,也就是没设置优化后的存放路径。其实optimizedDirectory为null时的默认路径就是/data/dalvik-cache 目录。
PathClassLoader是用来加载Android系统类和应用的类

ClassLoader加载class的过程
//BaseDexClassLoader
@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;
}

//DexPathList
public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;

        if (dex != null) {
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    if (dexElementsSuppressedExceptions != null) {
        suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
    }
    return null;
}

可以看出加载的过程就是

BaseDexClassLoader中有个pathList对象,pathList中包含一个DexFile的集合dexElements。类加载,就是遍历这个集合,通过DexFile去寻找。

其实本质就是:一个ClassLoader可以加载多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练与应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化与训练,到执行分类及结果优化的完整流程,并介绍了精度评价与通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者与实践者。; 使用场景及目标:①在遥感影像中自动识别提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程与关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优与结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置与结果后处理环节,充分利用ENVI Modeler进行自动化建模与参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值