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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android平台类加载流程源码分析

發布時間:2025/3/15 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android平台类加载流程源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

其實大家都知道的Android是使用Java作為開發語言,但是他使用的虛擬機卻并不是傳統的JVM,在4.4以前Android使用Dalvik虛擬機,之后使用ART(Android Runtime).

Dalvik和ART與傳統的JVM不同的地方在于,為了更加高效的在移動終端運行,Google重新定義了一套Dalvik字節碼,用于在Dalvik和ART虛擬機上運行.

因此如果你希望自己在本地生成的Java代碼能夠在Android機器上運行,就必須通過轉碼的形式生成一份Dex文件.

生成Dex文件

當我們完成Java代碼的書寫后,需要使用dx命令將Java代碼由javac生成的class文件編譯為Android虛擬機可識別的dex文件.

編譯命令如下

1 dx --dex --output 'dex' 'target'

其中dex代表將要輸出的dex文件名,target代表用于作為輸入的文件,可以為class或jar文件.

解壓生成的dex文件后,你會發現一個叫做classes.dex的文件,是不是很眼熟? 在每個Android的APK中都會存在這么一個文件,他才是所有代碼的集合,類似于class文件.

生成完了Dex文件,接下來,讓我們看看如何在Android設備上運行它.

加載Dex文件

下面是一個Dex文件加載的Demo:

1 Context context = getBaseContext(); 2 DexClassLoader loader = new DexClassLoader("/sdcard/demo.jar", 3 context.getCacheDir().getAbsolutePath(), null, context.getClassLoader()); 4 try { 5 Class<?> clazz = loader.loadClass("com.kifile.sample.Sample"); 6 Object object = clazz.newInstance(); 7 Method method = clazz.getDeclaredMethod("println"); 8 if (method != null) { 9 method.invoke(object); 10 } 11 } catch (ClassNotFoundException e) { 12 e.printStackTrace(); 13 } catch (InstantiationException e) { 14 e.printStackTrace(); 15 } catch (IllegalAccessException e) { 16 e.printStackTrace(); 17 } catch (NoSuchMethodException e) { 18 e.printStackTrace(); 19 } catch (InvocationTargetException e) { 20 e.printStackTrace(); 21 }

通過以上代碼,能夠從位于/sdcard/demo.jar的文件中讀取出一個”com.kifile.sample.Sample”類,并生成實例,動態調用其內部的”println”方法.

類加載流程分析

說了這么多了,都是教大家怎么在Android下動態加載java文件,現在我們來深入了解一下Android的類加載流程.

傳統Java類加載流程

首先對于我們先簡單說一下傳統的Java程序的類加載流程.

幾乎每一個Java類進行加載的時候都是通過ClassLoader進行加載的,當涉及引用新的類時,系統會自動調用當前類的ClassLoader區加載新類.

在加載的時候,首先判斷類有無加載,然后再從父ClassLoader中嘗試加載Class(之所以優先從父ClassLoader加載,是為了方便其他的兄弟ClassLoader能夠復用這個Class),當父ClassLoader也無法找到時,才通過findClass方法進行自查找.

Dex類加載流程

熟悉了這個之后,我們再來看看Android的類加載流程.

其實兩者的基本流程都是類似的:在能夠復用類的時候,盡量復用類,實在找不到Class,才自己去查找,但Android程序畢竟同普通的Java程序有所不同,

首先Android程序里所有組件的啟動均在ActivityThread中執行,同時在ActivityThread中會擁有一個LoadedApk的對象,在LoadedApk對象中,保存了包相關的數據,例如Dex文件和資源文件存放地址.

當我們啟動Application,Activity,Service等組件的時候,系統從LoadedApk中獲取ClassLoader對象,然后通過loadClass的方式,加載類.

這個ClassLoader對象就是PathClassLoader,因此對于Android應用而言,他幾乎所有的類都是通過PathClassLoader進行加載(除了諸如String,System等類,他們在Dalvik虛擬機創建時就注冊了).

所以我們需要關心的就是PathClassLoader的加載流程,PathClassLoader與上面樣例代碼中的DexClassLoader一樣繼承自BaseDexClassLoader.

我們看看BaseDexClassLoader類加載器的加載流程圖.

以上文件的源碼路徑分別為:

$ANDROID/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java $ANDROID/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java $ANDROID/libcore/dalvik/src/main/java/dalvik/system/DexFile.java $ANDROID/art/runtime/native/dalvik_system_DexFile.cc $ANDROID/art/runtime/native/java_lang_VMClassLoader.cc

如上所示,當DexClassLoader需要加載類時,先通過VMClassLoader查詢該類是否已經加載,如果尚未加載就通過創建時傳入的dexPath地址獲取到dex包路徑,然后根據Dex包路徑去實例化Class對象,并存入虛擬機中,然后返回.

當你成功的從ClassLoader獲取到Class時,其實在dalvik_system_DexFile中已經將當前類放置到ClassLoader對應的一張Hash表中,便于你下次重新獲取:

1 #$ANDROID/art/runtime/native/dalvik_system_DexFile.cc#DexFile_defineClassNative 2 class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile), 3 class_loader.Get()); 1 #$ANDROID/art/runtime/class_linker.cc#InsertDexFileInToClassLoader 2 class_table->InsertWithHash(klass, hash);

當我們通過ClassLoader獲取類時,通過以下代碼,將ClassLoader本身傳入本地代碼塊,從ClassLoader對應的Hash表中查詢類是否已經定義.

1 protected final Class<?> findLoadedClass(String className) { 2 ClassLoader loader; 3 if (this == BootClassLoader.getInstance()) 4 loader = null; 5 else 6 loader = this; 7 return VMClassLoader.findLoadedClass(loader, className); 8 }

以此,Android就完成了他的類加載流程.


原文地址:?http://blog.kifile.com/android/2015/11/10/dex_class_loader.html

總結

以上是生活随笔為你收集整理的Android平台类加载流程源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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