Android中ClassLoader和java中ClassLoader有什么关系和不同

一、Java中的ClassLoader是什么?

       当写好一个Java应用程序,程序都是由若干个.class类文件组织而成的,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到JVM中,从而只有class文件被载入到了JVM之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到JVM当中用的。

Android中ClassLoader和java中ClassLoader有什么关系和不同_第1张图片

简单的说Java中的ClassLoader就是加载 class 文件,提供给程序运行时使用。

二、java中ClassLoader加载原理

1、原理介绍

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时。加载过程是:

     1.源 ClassLoader 先判断该 Class 是否已加载,如果已加载,则直接返回 Class,如果没有则委托给父类加载器。

     2.父类加载器判断是否加载过该 Class,如果已加载,则直接返回 Class,如果没有则委托给祖父类加载器。

     3.依此类推,直到始祖类加载器(引用类加载器)。

     4.始祖类加载器判断是否加载过该 Class,如果已加载,则直接返回 Class,如果没有则尝试从其对应的类路径下寻找 class 字节码文件并载入。如果载入成功,则直接返回 Class,如果载入失败,则委托给始祖类加载器的子类加载器。

    5.始祖类加载器的子类加载器尝试从其对应的类路径下寻找 class 字节码文件并载入。如果载入成功,则直接返回 Class,如果载入失败,则委托给始祖类加载器的孙类加载器。

   6.依此类推,直到源 ClassLoader。

    7.源 ClassLoader 尝试从其对应的类路径下寻找 class 字节码文件并载入。如果载入成功,则直接返回 Class,如果载入失败,源 ClassLoader 不会再委托其子类加载器,而是抛出异常。

Android中ClassLoader和java中ClassLoader有什么关系和不同_第2张图片
jdk源码中的ClassLoader

2、JVM中是如何判定两个class是相同的呢?

      JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。

     同一个Class = 相同的 ClassName + PackageName + ClassLoader

如果想了解更加具体请看如下链接:

JVM 的工作原理,层次结构以及 GC 工作原理

深入分析Java ClassLoader原理

类加载机制:全盘负责和双亲委托


三、Android 中的 ClassLoader

    Android 的 Dalvik(5.0之前版本)/ART(5.0增加的) 虚拟机如同标准 Java 的 JVM 虚拟机一样,也是同样需要加载 class 文件到内存中来使用,但是在 ClassLoader 的加载细节上会有略微的差别。

    Android打包之后的apk 应用,将apk的后缀名改成zip或rar,解压之后会看见有一个或多个 class.dex 文件,用多个dex文件是android使用了MultiDexApplication解决65535的问题。


Android中ClassLoader和java中ClassLoader有什么关系和不同_第3张图片
多个dex文件

android在安装(installer)apk时,就对dex会进行验证和优化,同过一个专门的工具来处理,叫 DexOpt来进行处理,处理之后会产生ODEX文件,运行Apk的时候,直接加载ODEX,避免重复验证和优化,加快了Apk的响应时间。

总之,Android 中的 Dalvik/ART 无法像 JVM 那样直接加载 class 文件和 jar 文件中的 class,需要通过工具来优化转换成 Dalvik byte code 才行,只能通过 dex 或者包含 dex 的jar、apk 文件来加载(注意 odex 文件后缀可能是 .dex 或 .odex,也属于 dex 文件),因此 Android 中的 ClassLoader 工作就交给了 BaseDexClassLoader 来处理。

BaseDexClassLoader 及其子类

  从ClassLoader的android源码看ClassLoader是一个abstract类,其具体实现的子类有BaseDexClassLoader和SecureClassLoader。


Android中ClassLoader和java中ClassLoader有什么关系和不同_第4张图片
ClassLoader部门源码

  SecureClassLoader 的子类是URLClassLoader,其只能用来加载 jar 文件,这在 Android 的 Dalvik/ART 上没法使用的。

   BaseDexClassLoader 的子类是PathClassLoader和DexClassLoader。

PathClassLoader

 PathClassLoader 在应用启动时创建,从 data/app/… 安装目录下加载 apk 文件


Android中ClassLoader和java中ClassLoader有什么关系和不同_第5张图片
PathClassLoader源码

dexPath:文件或者目录的列表,dex,apk,多个以文件分隔符分隔,默认是“.”

librarySearchPath:包含lib库的目录列表,多个以文件分隔符分隔,默认是空格

parent:父类加载器

PathClassLoader 里面除了这 2 个构造方法以外就没有其他的代码了,具体的实现都是在 BaseDexClassLoader 里面,其 dexPath 比较受限制,一般是已经安装应用的 apk 文件路径。

在 Android 中,App 安装到手机后,apk 里面的 class.dex 中的 class 均是通过 PathClassLoader 来加载的。

DexClassLoader

A class loader that loads classes from.jar and.apk files containing aclasses.dexentry. This can be used to execute code not installed as part of an application.

根据官方给出的文档 DexClassLoader 可以从 SD 卡上加载包含 class.dex 的 .jar 和 .apk 文件,这也是插件化和热修复的基础,在不需要安装应用的情况下,完成需要使用的 dex 的加载。


Android中ClassLoader和java中ClassLoader有什么关系和不同_第6张图片
DexClassLoader源码

DexClassLoader类就只有一个方法,改方法有四个个参数

dexPath:dex文件路径列表,多个路径使用”:”分隔

dexOutputDir:经过优化的dex文件(odex)文件输出目录

libPath:动态库路径(将被添加到app动态库搜索路径列表中)

parent:这是一个ClassLoader,这个参数的主要作用是保留java中ClassLoader的委托机制(优先父类加载器加载classes,由上而下的加载机制,防止重复加载类字节码)

android的加载是根据BaseDexClassLoader子类进行加载不通的dex而子类的实现都在BaseDexClassLoader中,BaseDexClassLoader是关键,下次分析BaseDexClassLoader源码


你可能感兴趣的:(Android中ClassLoader和java中ClassLoader有什么关系和不同)