Java类加载机制

本文深入探讨Android中类加载机制,包括加载、验证、准备、解析和初始化五个阶段,重点解析热修复如何利用BaseDexClassLoader实现。通过自定义类加载器,如DexClassLoader和PathClassLoader,掌握Android系统类加载器的工作原理。

我们在平时面试中经常会被问到Android热修复的实现原理、Android插件化原理,这其是在对我们JVM类加载机制的一种考察。

1、类加载的过程主要分为:

(1)加载

把class字节码文件从各个来源通过类加载器装载入内存中。

说到加载就必须说一下java的类加载器,类加载器的任务就是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例。 BootstrapClassLoader、ExtClassLoader和AppClassLoader defineClass方法将字节码的byte数组转换为一个类的class对象实例,如果希望在类被记载到JVM时就被链接,那么可以调用resolveClass方法。

自定义类加载器需要继承抽象类ClassLoader,实现findClass方法,该方法会在loadClass调用的时候被调用,findClass默认会抛出异常。

findClass方法表示根据类名查找类对象

loadClass方法表示根据类名进行双亲委托模型进行类加载并返回类对象

defineClass方法表示跟根据类的字节码转换为类对象

Java中默认类加载器:

但是作为一个开发人员我们可能比较疑惑,在Android系统中我们常用的类加载器是:DexClassLoader和PathClassLoader

对此我们不必感到疑惑,其实Android的ClassLoader与Java的ClassLoader基本是一一对应的。

1、BootClassLoader(Java的BootStrap ClassLoader)
     用于加载Android Framework层class文件。
2、PathClassLoader(Java的App ClassLoader)
     用于加载已经安装到系统中的apk中的class文件。
3、DexClassLoader(Java的Custom ClassLoader)
     用于加载指定目录中的class文件。
4、BaseDexClassLoader
     是PathClassLoader和DexClassLoader的父类。


Android中ClassLoader的特点——遵循双亲委派模型:

ClassLoader在加载一个class文件时:会询问当前ClassLoader是否已经加载过子类,如果已经加载过则直接返回,不再重复加载。如果没有加载过,会去查询当前ClassLoader的parent是否已经加载过。

我们开发中遇到的热修复设计就是利用了这一原理。

Android中的classLoader具有以下特点:

1、当一个class文件被任何一个ClassLoader加载过,就不会再被其他ClassLoader加载。

2、不同ClassLoader加载的class文件肯定不是一个。

通过查看源码我们可以发现,其实我们在设计热修复功能的时候一般是利用的BaseDexClassLoader这个构造器的核心方法findClass()和其重要属性dexElements通多Java反射原理插入的我们修复的bug文件。

有时间我会写一个简版热修复功能模块放在Android高级专栏。

(2)验证

主要是为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。

(3)准备

主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值。

特别需要注意,初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不同变量类型的默认初始值。

比如8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值,final static tmp = 456, 那么该阶段tmp的初值就是456

(4)解析

将常量池内的符号引用替换为直接引用的过程。

主要有两点:

1、符号引用。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。

2、直接引用。可以理解为一个内存地址,或者一个偏移量。比如类方法,类变量的直接引用是指向方法区的指针;而实例方法,实例变量的直接引用则是从实例的头指针开始算起到这个实例变量位置的偏移量

举个例子来说,现在调用方法hello(),这个方法的地址是1234567,那么hello就是符号引用,1234567就是直接引用。在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。

(5)初始化

这个阶段主要是对类变量初始化,是执行类构造器的过程。换句话说,只对static修饰的变量或语句进行初始化。如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。



 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值