Android的熱修復技術在去年因為大廠們的支持和分享所以出現了一些不同的解決方案,如QQ空間補丁方案、阿里AndFix以及微信Tinker,我們查閱相關資料后會發現QQ和微信的解決方案其實原理是一樣的,都是基于Google推出的的Multidex方案,以ClassLoader的方式完成問題類的替換,談到ClassLoader我們就不得不了解下java的類加載機制了。
類的加載過程 JVM將類加載過程分為三個步驟:裝載(Load),鏈接(Link)和初始化(Initialize)鏈接又分為三個步驟
裝載: 查找并加載類的二進制數據;鏈接: 驗證:確保被加載類信息符合JVM規范、沒有安全方面的問題。 準備:為類的靜態變量分配內存,并將其初始化為默認值。 解析:把虛擬機常量池中的符號引用轉換為直接引用。初始化: 為類的靜態變量賦予正確的初始值。 常量池:Java 中,虛擬機會為每個加載的類維護一個常量池【不同于字符串常量池,這個常量池只是該類的字面值(例如類名、方法名)和符號引用的有序集合。 而字符串常量池,是整個JVM共享的】這些符號(如int a = 5;中的a)就是符號引用,而解析過程就是把它轉換成指向堆中的對象地址的相對地址。在準備階段初始化默認的值就是0。 類的初始化工作
創建類的實例,也就是new一個對象訪問某個類或接口的靜態變量,或者對該靜態變量賦值調用類的靜態方法反射(Class.forName(“com.xxx.android.activity.xx”))初始化一個類的子類(會首先初始化子類的父類)JVM啟動時標明的啟動類,即文件名和類名相同的那個類(包含static void main(String[] args)的那個類)類的加載器 我們在ide里面寫的各種Java文件編譯成class文件后,類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,最終被jvm放在位于堆區中的Class對象,執行這個過程的是由類加載器完成的。這里我們普通說的是把.class文件中二進制數據讀入內存,其實還有以下幾張方式,很多技術都是在這里切入,因為它并沒有限定二進制流從哪里來,例如:
從zip包中來->加載jar中的類 從網絡中來->Applet ……….ClassLoader:是Java層幾乎所有類加載器的父類,根本它的功能基本上可以分為四大類:
1. 啟動類加載器(Bootstrap ClassLoader):
這個類加載器負責將<JAVA_HOME>/lib目錄下的類庫加載到虛擬機內存中,用來加載java的核心庫,此類加載器并 不繼承于java.lang.ClassLoader,不能被java程序直接調用,代碼是使用C++編寫的.是虛擬機自身的一部分.2.擴展類加載器(Extendsion ClassLoader):
這個類加載器負責加載<JAVA_HOME>/lib/ext目錄下的類庫,用來加載java的擴展庫,開發者可以直接使用這個類加載器.3. 應用程序類加載器(application ClassLoader):
應用程序類加載器負責加載用戶類路徑中的文件。用于加載我們自己定義編寫的類。4. 用戶自定義類加載器(Custom ClassLoader):
屬于應用程序根據自身需要自定義的ClassLoader,例如QQ空間補丁方案等等。類的雙親委派模型

結論:
簡單來說就是,先檢查需要加載的類是否已經被加載過,如果沒有則請求委派上一級進行判斷,逐次遞歸向上一級委派,這個過程是從下到上;如果走到頂級Bootstrap ClassLoader判斷還是沒有加載過,那么就從Bootstrap開始往下級嘗試進行加載,這個過程是從上到下。 如果它們都沒有加載到這個類時,則拋出ClassNotFoundException異常。否則將這個找到的類生成一個類的定義,并將它加載到內存當中,最后返回這個類在內存中的Class實例對象。
好處:
1.以避免重復加載,當父親已經加載了該類的時候,就沒有必要子ClassLoader再加載一次。
2.安全,如果不使用這種委托模式,那我們就可以隨時使用自定義的String來動態替代java核心api中定義的類型,這樣會存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因為String已經在啟動時就被引導類加載器(Bootstrcp ClassLoader)加載,所以用戶自定義的ClassLoader永遠也無法加載一個自己寫的String,除非你改變JDK中ClassLoader搜索類的默認算法。
JVM如何判定兩個類你是否相等:
JVM在判定兩個class是否相同時,不僅要判斷兩個類名是否相同,而且要判斷是否由同一個類加載器實例加載的。只有兩者同時滿足的情況下,JVM才認為這兩個class是相同的。
日常開發中我們基本接觸不到需要自己定義類加載器的需求,因為jvm自帶的幾大類加載器已經完全可以滿足我們的開發需求,但是需要我們動態加載外部的class文件的時候就會用到,Google官網為了解決Android4.x系統中65k方法數限制,推出Multidex解決方案,將一個完整的APK中的Dex拆分成好幾個dex,通過PathClassLoader 這個加載器來加載,QQ空間開發正是利用了這一點在Google定義的這個PathClassLoader 類加載器的加載過程中做了一些文章,通過網路下載到修復的.class文件替換了原來同類名的.class文件從而在線修復了bug。當然還有其他熱修復解決方案例如阿里百川HotFix 等,讀者可以自己查資料學習,這里就不說了。
新聞熱點
疑難解答