前面給你們講解了 Java 虛擬的內存結構 以及 Java 虛擬機的垃圾回收機制,咱們更加明白了 Java 的內存管理機制,今天咱們來說講 Java 虛擬機的另一個高頻考點:類加載機制。java
JVM 的類加載過程分爲加載、驗證、準備、解析、初始化 5 個階段。設計
加載階段由類加載器進行負責,類加載器根據一個類的全限定名讀取該類的二進制字節流到 JVM 內部,而後轉換爲一個對應的 java.lang.Class 對象實例;一個類由類加載器和類自己一塊兒肯定,因此不一樣類加載器加載同一個類獲得的 java.lang.Class 也是不一樣的。code
驗證階段負責驗證類數據信息是否符合 JVM 規範,是不是一個有效的字節碼文件。對象
準備階段是正式爲類變量(static 修飾的變量)分配內存並設置類變量初始值的階段,這些內存都將在方法區進行分配。繼承
這個階段由兩個容易產生混淆的概念須要強調一下,首先是這時候進行內存分配的僅包括類變量,而不包括實例變量,實例變量將會在對象實例化時隨着對象一塊兒分配在 Java 堆中。其次這裏所說的初始值在沒有被 final
修飾的時候都是數據類型的零值,只有相似 public static final int value = 1024
這樣的狀況下才回直接被賦值 123。內存
解析階段是虛擬機將常量池內的「符號引用」替換爲「直接引用」的過程。開發
初始化階段負責將全部的 static 域按照程序指定操做對應執行(賦值 static 變量,執行 static 塊)。get
上述階段一般都是交叉混合容許,沒有嚴格的前後執行順序。虛擬機
站在 Java 虛擬機的角度講,只存在兩種不一樣的類加載器:一種是啓動類加載器,這個類加載器使用 C++ 語言實現,是虛擬機自身的一部分,另一種是全部其餘的類加載器,這種類加載器都由 Java 語言實現,獨立於虛擬機外部,而且所有繼承自抽象類 java.lang.ClassLoader
。內存管理
雙親委派模型並非一個強制性的約束模型,而是 Java 設計者們推薦給開發者們的類加載器實現方式。它的工做過程是:若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每個層次的類加載器都是如此,所以全部的加載請求最終都應該傳送到頂層的類加載器中,只有當父加載器反饋本身完成這個加載請求的時候,子加載器纔會嘗試本身去加載。
使用雙親委派模型來組織類加載器之間的關係,有一個顯而易見的好處就是 Java 類隨着它的類加載器一塊兒具有了一種帶有優先級的層次關係。
好比黑客定義一個 java.lang.String 類,該 String 類和系統 String 類有同樣的功能,只是在某個方法好比 equels() 中加入了病毒代碼,而且經過自定義類加載器加入 JVM 中,若是沒有雙親委派模型,那麼 JVM 就可能誤覺得黑客編寫的 String 類是系統 String 類,致使「病毒代碼」最終被執行。而有了雙親委派模型,黑客定義的 java.lang.String 類就用於不會被加載進內存,由於最頂端的類加載器會加載系統的 String 類,最終自定義的類加載器沒法加載 java.lang.String 類。
能夠經過重寫 loadClass() 方法,打破雙親委派模型。
最近的知識比較枯燥,但仍是咱們所必須瞭解的。
參考文獻:《深刻理解 Java 虛擬機》