主要講述:
1. .class文件如何加載到內存
2. 加載到內存之后做了什么。
首先是概念,什么是類加載機制?
將類的數據從Class文件加載到內存,并對數據進行校驗、轉換解析和初始化,最終形成可以被JAVA虛擬機使用的類型。
一、類的加載時機
類的生命周期分為:
1.加載階段,注意區分類的加載機制,和加載階段,加載階段,只是讀入 .Class 二進制流進內存。
2.鏈接,又分為,驗證,準備,解析。
3.初始化
4.使用
5.卸載
*** 什么時候去加載一個類?
加載階段是任意的。
初始化階段有嚴格的限制,有且只有以下5種情況,必須立即進行初始化:
1.new 一個對象,調用類的靜態方法,使用類的靜態變量(final修飾的不算,在編譯階段已經放到常量區了)
2.反射一個對象
3.初始化一個類的時候,發現其父類沒有初始化,先初始化這個父類。
4.虛擬機啟動的時候,執行main函數的那個主類。
5. JDK 1.7動態語言支持。
接口類有不同:
接口類初始化的時候,不回去初始化接口類的父類。
各個過程描述
1.加載階段
包括三件事:
a.以全限定名字得到類的二進制字節流。
b.將這個字節流所代表的靜態結構轉化為方法區的運行時數據結構。
c.在內存中生成類的Class對象。
注意,一個加載器和一個類,唯一確定了JVM中的一個類。
2.驗證
就是各種驗證
3.準備
為類變量分配內存并設置初始值。注意這個初始值與類無關(int 的值都賦成0)。與類相關的階段叫做 初始化 。
4.解析
就是各種解析。
5.初始化
初始化階段,開始執行Java代碼。
初始化階段,其實就是執行 <clinit> 方法的過程。
<clinit>方法,里面含有,所有類變量的賦值動作和靜態語句塊中的語句。前面這兩種操作的優先級相同,各個操作按順序執行。
<clinit>方法保證,在子類<clinit>方法執行之前,父類的<clinit>執行完畢。
接口可能沒有<clinit>方法,接口不能使用靜態塊,接口可以使用靜態賦值。
*重點*,虛擬機會保證一個類的 <clinit>方法只會被一個線程執行。所以 static 變量的復制初始化等操作,都是安全的(static Test test = new Test())。
類加載器
加載這個類的類加載器和這個類,兩個確定了一個類在JVM中的唯一性。
這里說的相等,指的是,equals、instanceof等方法。
類加載器的種類:
1.從虛擬機的角度來看,只有兩種,一種是啟動類加載器(bootstrap classloader),虛擬機的一部分,用c++寫。2.其他的加載器,用java寫。
系統提供了三種加載器:
1.啟動類加載器
2.擴展類加載器
3.應用程序加載器(一般程序默認使用)
雙親委派模型:
要求每個加載器都要有一個父類。
工作過程:
每次加載器收到一個加載請求,會先交給父類,看父類能不能加載。會一直上傳到頂層。