1、類的加載過程java
一、加載:c++
1.一、經過類的全限定名來獲取類的二進制字節流。編程
1.二、將字節流轉換爲方法區的運行時數據結構。安全
1.三、在內存中生成表明該類的java.lang.Class對象,做爲該類的訪問入口。網絡
二、驗證數據結構
2.一、驗證字節流是否符合Class文件規範。多線程
2.二、對字節碼描述的語義進行分析。spa
2.三、驗證語義的合法性。線程
三、準備指針
3.一、在方法區中,爲類變量(static修飾的變量)分配內存,並賦初始化值。(初始化值:根據數據的默認類型設置零值)
初始化值舉例:
public static int value = 123;
那麼準備階段執行完後,value = 0 。在初始化階段,才變爲 value = 123 。
四、解析
4.一、將常量池的符號引用替換爲直接引用。
符號引用:符號引用以一組符號來描述所引用的目標,符號能夠是任何形式的字面量,只要能惟一標識目標便可。
直接引用:直接引用能夠是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。
舉例:
public class A{
private List<Object> lists;
}
用類A的加載器,根據List的全限定名,加載List類,並將加載後的List類的訪問入口,指向lists這個變量。(符號引用替換爲直接引用)
五、初始化
5.一、初始化階段,編譯器將執行全部類變量、靜態語句塊的賦值動做。
執行初始化的順序爲:
根據語句在源文件中的前後順序來順序執行。先執行父類的初始化,再執行子類的初始化。
注意:
虛擬機會保證多線程環境下,初始化過程只能執行一次。
2、類加載器
類加載器:經過類的全限定名來獲取類的二進制字節流。
類加載器分爲兩種:
啓動類加載器:c++語言實現,虛擬機的一部分。
其餘類加載器:繼承於java.lang.ClassLoader。
啓動類加載器:負責將<JAVA_HOME>\lib目錄下的,類庫加載到虛擬機中。
擴展類加載器:加載<JAVA_HOME>\lib\ext 目錄中的類,能夠被開發者直接使用。
應用程序加載器:負責加載用戶類庫路徑(ClassPath)中的類庫,能夠被開發者直接使用。
自定義類加載器:加載自定義的類庫。
雙親委派模型工做過程:
若是一個類加載器收到了類的加載請求,它首先不會本身去嘗試加載這個類,而是把這個加載請求委派給父類加載器去完成,每個層次的類加載器都是如此。所以全部的加載請求最終都會傳遞到頂層的啓動類加載器中,只有當父類加載器反饋本身沒法完成加載請求(在本身的搜索範圍內,找不到該類)時,子類纔會去嘗試本身去加載。
雙親委派模型的意義:
一、確保惟一性。肯定一個class的惟一性是由類加載器和對應的class來惟一肯定的。若是不適應雙親模型,那麼根類加載器和系統類加載器都加載了一個名爲String的類,那麼在使用的時候,值同樣的對象equals就不相等。
二、安全性。防止經過網絡的形式,篡改系統庫,即rt.jar。
雙親委託模型的缺點:
一、父加載器所加載的類,沒法使用子加載器所加載的類。(解決的方法:線程上下文類加載類)
每個類都會使用自身的類加載器來加載所依賴的類。
線程上下文類加載器:
在面向接口的編程環境下,接口類是類庫定義的,實現類是任意的。那麼啓動類加載器能夠加載到接口類,可是如何識別實現類呢?此時就須要到線程上下文類加載器。
線程上下文類加載器(Thread Context ClassLoader)。Thread類中有getContextClassLoader()和setContextClassLoader(ClassLoader cl)方法用來獲取和設置上下文類加載器,若是沒有setContextClassLoader(ClassLoader cl)方法經過設置類加載器,那麼線程將繼承父線程的上下文類加載器,若是在應用程序的全局範圍內都沒有設置的話,那麼這個上下文類加載器默認就是應用程序類加載器(Application ClassLoader),換句話說Java默認的線程上下文類加載器就是應用程序類加載器(AppClassLoader)。
通常使用模式:
類的卸載:僅自定義加載器所加載的類,才能進行卸載。