日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一步步手动实现热修复(二)-类的加载机制简要介绍

發布時間:2024/7/5 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步步手动实现热修复(二)-类的加载机制简要介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

*本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發布

本節課程主要分為3塊:

  • 1.一步步手動實現熱修復(一)-dex文件的生成與加載
  • 2.一步步手動實現熱修復(二)-類的加載機制簡要介紹
  • 3.一步步手動實現熱修復(三)-Class文件的替換

本節示例所用到的任何資源都已開源,項目中包含工程中所用到代碼、示例圖片、說明文檔。項目地址為:
https://code.csdn.net/u011064099/sahadevhotfix/tree/master


本節內容是為了給下節內容做知識鋪墊,所以如果要需要了解熱修復技術,本節內容的知識點必不可少。

一個類在被加載到內存之前要經過加載、驗證、準備等過程。經過這些過程之后,虛擬機才會從方法區將代表類的運行時數據結構轉換為內存中的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 loadedClass<?> 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 statssun.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()實現:

@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {Class clazz = pathList.findClass(name);if (clazz == null) {throw new ClassNotFoundException(name);}return clazz;}

Tips: 有需要虛擬機以及類加載器全套代碼的,請使用以下命令克隆:
git clone https://android.googlesource.com/platform/dalvik-snapshot
相關代碼位于項目的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);

到此為止,我們就將類的加載過程梳理完了。

下一節課我們將會介紹如何實現類的替換。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的一步步手动实现热修复(二)-类的加载机制简要介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。