字節碼(.class)文件的加載過程


類加載

 在Java代碼中,類型的加載、連接與初始化過程都是在程序運行期間完成的。

類型可以是Class,Interface, 枚舉等。

 

Java虛擬機與程序的生命周期

在如下幾種情況下,Java虛擬機將結束生命周期

1)執行了System.exit() 方法

2)程序正常執行結束

3)程序在執行過程中遇到了異常或者錯誤而異常終止。

4) 由於操作系統出現錯誤導致Java虛擬機進程終止。

 

字節碼文件的裝載過程: 加載、連接(包括三個步驟: 驗證 准備  解析)、初始化

加載:查找並加載類的二進制數據

連接:

  驗證:確保被加載的類的正確性

  准備:為類的靜態變量分配內存,並將其初始化為默認值

  解析:把類中的符號引用轉換為直接引用

    符號引用:通俗的講,是一種間接引用,如一個類中的方法引用了另外一個類,這是一種符號的表述。

         直接引用:就是通過指針的方式,直接指向了目標對象內存的位置,這樣能一下子找到特定的方法。

初始化: 為類的靜態變量賦予正確的初始值

 

 

一、類裝載的條件

Java程序對的使用方式分為兩種

主動使用 

被動使用

所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才初始化他們。

 

Java虛擬機規定: 一個類或者接口在初次使用時,必須進行初始化。

這里的使用指主動使用,主動使用有以下幾種情況

1) 當創建一個類的實例時。 比如使用new關鍵字,或者通過反射、克隆、反序列化方式。

2) 當調用類的靜態方法時。即當使用了字節碼invokestatic指令

3)當使用類或者接口的靜態字段時(final常量除外,此種情況只會加載類而不會進行初始化),即使用getstatic或者putstatic指令(可以使用jclasslib軟件查看生成的字節碼文件),或者對該靜態字段賦值(putstatic指令)。

4)當使用java.lang.reflect包中的方法反射類的方法時。如Class.forName("com.example.Test")

5)當初始化子類時,必須先初始化父類

6)作為啟動虛擬機,含有main方法的那個類

7)JDK1.7開始提供的動態語言支持

java.lang.invoke.MethodHandle實例的解析結果REF_getStatic, REF_putStatic,REF_invokeStatic句柄對應的類沒有初始化,則初始化。

除了以上情況屬於主動使用外,其他情況均屬於被動使用,被動使用不會引起類的初始化,只是加載了類卻沒有初始化。(這里的初始化就是類加載的第三個階段)

 

主動類和被動類的使用

 

二、類裝載的過程

1、加載類: 處於類裝載的第一個階段

1.1 類的加載指的是將類的.class 文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然后在內存中創建一個java.lang.Class對象(規范中並未說明Class對象位於哪里,HotSpot虛擬機將其放在方法區中),用來分裝類在方法區內的數據結構。

加載類時,JVM必須完成

1)通過類的全名,獲取類的二進制數據流。

2)解析類的二進制數據流為方法區內的數據結構,也就是將類文件放入方法區中

3)創建java.lang.Class類的實例,表示該類型

 

1.2 加載.class 文件的方式

從本地系統中直接加載

通過網絡下載.class文件

從zip,jar等文檔文件中加載.class 文件

從專有數據庫中提取.class文件

將Java源文件動態編譯為.class 文件(動態代理,JSP(JSP文件本質上是Sevlet,最終被編譯為.class文件))

 

 

 

2、連接

2.1 驗證字節碼

驗證字節碼文件: 當類被加載到系統后,就開始連接操作,驗證就是連接的第一步

主要目的是保證加載的字節碼是否符合規范

驗證的步驟如圖:

 

 2.2 准備階段

當一個類通過驗證后,虛擬機就會進入准備階段。准備階段是正式為類變量(static修飾的變量)分配內存並設置類變量初始值,這些內存都將在方法區進行分配。這個時候進行內存分配的僅是類變量,不包括類實例變量,實例變量將會在對象實例化時隨着對象一起分配在堆上。為類變量設置初始值是設為其數據類型的“零值”。

比如: public static int num = 10; 這個時候就會為num變量賦值為0

Java虛擬機為各種類型變量默認的初始值如表:

注意:java並不支持boolean類型,對於boolean類型,內部實現試Int, 由於int的默認值是0, 故對應的boolean的默認值是false。

如果類中屬於常量的字段,那么常量字段也會在准備階段被附上正確的值,這個賦值屬於java虛擬機的行為,屬於變量的初始化。在准備階段,不會有任何java代碼被執行。

 

2.3 解析類

解析階段的任務就是將類、接口、字段和方法的符號引用直接轉為直接引用。

符號引用就是一些字面量的引用。比較容易理解的就是在Class類文件中,通過常量池進行大量的符號引用。

 

3、初始化

為類的靜態變量賦予正確的初始值

 

三、類的使用和卸載

除了上面三個步驟,加載,連接,初始化,還有下面兩個過程:使用和卸載

4、使用: 如類創建一個對象,調用類里的方法。

5、卸載:.class 文件加載到內存中,形成了一個自己的數據結構駐留在內存中,還可以從內存中銷毀掉,稱之為卸載。

     卸載以后,就不能再創建類的對象了。可以重新加載到內存中。(開發人員很少使用卸載)

以上就是類加載的5個過程。

 

參考: https://blog.csdn.net/qq_20610631/article/details/82709187


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM