博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一步步手动实现热修复(二)-类的加载机制简要介绍
阅读量:6046 次
发布时间:2019-06-20

本文共 4208 字,大约阅读时间需要 14 分钟。

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

本节课程主要分为3块:

  • 1.
  • 2.
  • 3.

本节示例所用到的任何资源都已开源,项目中包含工程中所用到代码、示例图片、说明文档。项目地址为:


本节内容是为了给下节内容做知识铺垫,所以如果要需要了解热修复技术,本节内容的知识点必不可少。

一个类在被加载到内存之前要经过加载、验证、准备等过程。经过这些过程之后,虚拟机才会从方法区将代表类的运行时数据结构转换为内存中的Class。

我们这节内容的重点在于一个类是如何被加载的,所以我们从类的加载入口开始。

类的加载是由虚拟机触发的,类的加载入口位于ClassLoader的loadClassInternal()方法:

// This method is invoked by the virtual machine to load a class.    private Class
loadClassInternal(String name) throws ClassNotFoundException { // For backward compatibility, explicitly lock on 'this' when // the current class loader is not parallel capable. if (parallelLockMap == null) { synchronized (this) { return loadClass(name); } } else { return loadClass(name); } }

这段方法还有段注释说明:这个方法由虚拟机调用用来加载一个类。我们看到这个类的内部最后调用了loadClass()方法。那我们进入loadClass()方法看看:

public Class
loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }

loadClass()方法方法内部调用了loadClass()的重载方法:

protected Class
loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class
c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }

loadClass()方法大概做了以下工作:

  • 首先查找该类是否已经被加载.
  • 如果该ClassLoader有父加载器,那么调用父加载器的loadClass()方法.
  • 如果没有父加载器,则调用findBootstrapClassOrNull()方法进行加载,该方法会使用引导类加载器进行加载。普通类是不会被该加载器加载到的,所以这里一般返回null.
  • 如果前面的步骤都没找到,那调用自身的findClass()方法进行查找。

好,ClassLoader的findClass()方法是个空方法,所以这个过程一般是由子加载器实现的。Java的加载器这么设计是有一定的渊源的,感兴趣的读者可以自行查找书籍了解。

protected Class
findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }

在Android中,ClassLoader的直接子类是BaseDexClassLoader,我们看一下BaseDexClassLoader的findClass()实现:

@Override    protected Class
findClass(String name) throws ClassNotFoundException { Class clazz = pathList.findClass(name); if (clazz == null) { throw new ClassNotFoundException(name); } return clazz; }

Tips: 有需要虚拟机以及类加载器全套代码的,请使用以下命令克隆:

git clone
相关代码位于项目的ics-mr1分支上。

看到这里我们可以知道,Android中类的查找是通过这个pathList进行查找的,而pathList又是个什么鬼呢?

在BaseDexClassLoader中声明了以下变量:

/** structured lists of path elements */    private final DexPathList pathList;

所以我们可以看看DexPathList的findClass()方法做了什么:

public Class findClass(String name) {        for (Element element : dexElements) {            DexFile dex = element.dexFile;            if (dex != null) {                Class clazz = dex.loadClassBinaryName(name, definingContext);                if (clazz != null) {                    return clazz;                }            }        }        return null;    }

这里通过遍历dexElements中的Element对象进行查找,最终走的是DexFile的loadClassBinaryName()方法:

public Class loadClassBinaryName(String name, ClassLoader loader) {        return defineClass(name, loader, mCookie);    }    private native static Class defineClass(String name, ClassLoader loader, int cookie);

到此为止,我们就将类的加载过程梳理完了。

下一节课我们将会介绍如何实现类的替换。

转载地址:http://htiex.baihongyu.com/

你可能感兴趣的文章
执行SQL语句,返回新插入的主键值
查看>>
a标签弹出 文件上载框
查看>>
非windows下 php连接mssql FreeTDS配置
查看>>
解决actionSheet在iOS4.3中不能正常使用的问题
查看>>
学习之路二十九:泛型和委托在重构中的运用
查看>>
iOS 响应链
查看>>
节点利用js的Node 遍历找到repeater的一个字段 实例
查看>>
C编译: makefile基础
查看>>
5个jQuery的备选轻量级移动客户端开发(Mobile development)类库
查看>>
继承虚函数单层需继承的内存图(VC6.0)
查看>>
hdu 2149+hdu 1846(巴什博弈)
查看>>
Google免费的SVN服务器管理VS2010代码
查看>>
Spring_集合装配
查看>>
点阵字体, 矢量字体
查看>>
中断详细分析
查看>>
Integer.valueof() Integer.parseInt()
查看>>
python数字图像处理(15):霍夫线变换
查看>>
Codeforces 482B Interesting Array(线段树)
查看>>
form不提交问题
查看>>
web desktop在线演示
查看>>