類的生命週期


其中類加載的過程包括加載、驗證、準備、解析、初始化 5個階段

加載

  1. 主要做三件事情:
    1)通過一個類的全限定名來獲取定義此類的二進制字節流
    2)將這個字節流的靜態存儲結構轉換成方法區(類信息存儲在永久代,類卸載就是對永久代的垃圾收集)的運行時數據結構
    3)在Java堆中生成一個代表這個類的Class對象,作爲方法區這些數據的訪問入口
  2. 第一點獲取類的二進制字節流並沒有限定從哪裏獲取,現有以下幾種參見方式:
    1)從ZIP中獲取,如jar,ear,war中加載
    2)從網絡中獲取,如applet
    3)運行時計算生成,比較出名的就是動態代理技術
    4)其他文件生成,如JSP文件
    5)從數據庫中讀取,有些服務器會把程序安裝到數據庫中來完成代碼在集羣中的分發
    這個獲取類的二進制字節流這個動作的代碼模塊就是類加載器,詳見博文“類加載器”

驗證

  1. 驗證時連接的第一步,爲了確保class文件的字節流中包含的信息符合虛擬機要求,不會危害虛擬機安全,主要包括文件格式驗證、元數據驗證、字節碼驗證和符號引用驗證
    1)文件格式:如 魔數0xCAFEBABE,主次版本是否在虛擬機處理範圍內(低版本虛擬機無法加載高版本的class文件),常量類型、編碼格式是否符合等。。。
    這個驗結束後字節流就會進入方法區
    2)元數據驗證:如 除了object都要有父類,是否繼承了final的類,非抽象類是否實現了父類或接口中所有要實現的方法,類中字段、方法名是否覆蓋了父類的final字段、方法等。。。
    3)字節碼驗證:這階段對類的方法進行校驗,如 在棧中放置一個int但卻當作long來使用,不會跳到方法體以外的字節碼上,保證方法體內類型轉換是有效的,如把父類對象賦值給子類數據類型就是不合法的,等。。。
    4)符號引用驗證:主要是爲了保證解析動作能正常執行,通過字符串全限制名能否找到對應的類,在指定類中是否存在描述中的方法和字段,類、方法和字段能否被當前類訪問等。。。

準備

在方法區中分配static變量的初始值,如:
public static int value = 123;
在準備階段結束後值爲0,在初始化的時候給value賦值
但是如果是常量,如:
public static final int value = 123;
那麼在準備階段虛擬機就會把value的值複製爲123

解析

解析階段就是把常量池中的符號引用替換成直接引用
1)符號引用:以一組符號來描述所引用的目標,符號可以是任何形式的字面量
2)直接引用:直接指向目標的指針、相對偏移量或者句柄

初始化

  1. 解析可以在初始化之後再開始,也就是常說的Java運行時綁定(動態綁定)
  2. 有4種情況可以觸發類的初始化
    1)遇到new(實例化對象)、getstatic(讀取類的靜態字段)、putstatic(設置類的靜態字段)、invokestatic(調用一個類的靜態方法)
    2)對類進行反射調用
    3)之類被初始化的時候,先觸發父類的初始化
    4)虛擬機啓動時,會初始化一個用戶指定的主類(包含main方法的那個)
    類與接口的區別是第三點,接口初始化的時候,並不要求其父接口全部都完成了初始化,只有真正用到父接口的時候纔會初始化
  3. 初始化就是執行類構造器clinit()方法的過程,clinit方法是類中所有類變量的賦值動作和靜態語句塊的集合,父類的clinit先執行,所以虛擬機中第一個被執行clinit的類肯定是Object
發佈了81 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章