深入理解Java虚拟机——类加载机制
一 概述
?
虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗、 轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。?
與那些在編譯時需要進行連接工作的語言不同,在Java語言里面,類型的加載、 連接和初始化過程都是在程序運行期間完成的?。
二 類加載的時機
?
?
2.1 類的生命周期
?
?
圖片來源于《深入理解Java虛擬機》
加載、 驗證、 準備、 初始化和卸載這5個階段的順序是確定的?,而解析階段則不一定?,這是為了支持動態(tài)綁定。?
2.2 什么時候開始
什么時候開始加載,Java虛擬機規(guī)范中并沒有進行強制約束,但是對于初始化階段,虛擬機規(guī)范則是嚴格規(guī)定了有且只有5種情況必須立即對類進行“初始化”(而加載、 驗證、 準備自然需要在此之前開始),以下情況下,若類沒有進行過初始化,則需要觸發(fā)其初始化:
(1)遇到new、 getstatic、 putstatic或invokestatic這4條字節(jié)碼指令時。常見場景:使用new關(guān)鍵字實例化對象的時候、 讀取或設(shè)置一個類的靜態(tài)字段(被final修飾、 已在編譯期把結(jié)果放入常量池的靜態(tài)字段除外)的時候,以及調(diào)用一個類的靜態(tài)方法的時候。?
(2)使用java.lang.reflect包的方法對類進行反射調(diào)用的時候?。
(3)當初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進行過初始化,則需要先觸發(fā)其父類的初始化。?
注意:接口在初始化時,并不要求其父接口全部都完成了初始化,只有在真正使用到父接口的時候(如引用接口中定義的常量)才會初始化。?
(4)當虛擬機啟動時,用戶需要指定一個要執(zhí)行的主類(包含main()方法的那個類),虛擬機會先初始化這個主類?。(5)如果一個java.lang.invoke.MethodHandle實例最后的解析結(jié)果是REF_getStatic、 REF_putStatic、 REF_invokeStatic的方法句柄?。
三 類加載的過程
?
加載過程包括:加載、 驗證、 準備、 解析和初始化?。
3.1 加載
?
?
此階段完成三件事:
(1)通過一個類的全限定名來獲取定義此類的二進制字節(jié)流。
(2)將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
(3)在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。
?
加載階段完成后,虛擬機外部的二進制字節(jié)流就按照虛擬機所需的格式存儲在方法區(qū)之中?,加載階段和連接階段是交叉進行的。
3.2 驗證
目的是為了確保Class文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。?
3.3 準備
準備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進行分配。 這時候進行內(nèi)存分配的僅包括類變量(被static修飾的變量),而不包括實例變量,實例變量將會在對象實例化時隨著對象一起分配在Java堆中。??
3.4 解析
解析階段是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程?。
3.5 初始化
到了初始化階段,才真正開始執(zhí)行類中定義的Java程序代碼?。在準備階段,類變量已經(jīng)賦過一次系統(tǒng)要求的初始值,而在初始化階段,則根據(jù)程序員通過程序制定的主觀計劃去初始化類變量和其他資源?。
四 類加載器
?
從Java虛擬機的角度來講,只存在兩種不同的類加載器?:一種是啟動類加載器(Bootstrap ClassLoader),這個類加載器使用C++語言實現(xiàn),是虛擬機自身的一部分;另一種就是所有其他的類加載器,這些類加載器都由Java語言實現(xiàn),獨立于虛擬機外部,并且全都繼承自抽象類java.lang.ClassLoader。
Bootstrap ClassLoader?:負責將存放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath參數(shù)所指定的路徑中的,并且是虛擬機識別的類庫加載到虛擬機內(nèi)中。
Bootstrap ClassLoader?:負責加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以直接使用。
Application ClassLoader:它負責加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。
五?雙親委派模型?
?
?
來源于《深入理解Java虛擬機》
?
?
如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。
總結(jié)
以上是生活随笔為你收集整理的深入理解Java虚拟机——类加载机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MPU6050开发 -- Linux下测
- 下一篇: Hi3516A开发-- OSD功能实现