jvm生命週期之類的加載、鏈接、初始化

加載

       在java中,咱們常常會接觸到一個詞——類加載,它和這裏的加載並非一回事,一般咱們說類加 載指的是類的生命週期中加載、鏈接、初始化三個階段。在加載階段,java虛擬機會作什麼工做呢?其實很簡單,就是找到須要加載的類並把類的信息加載到 jvm的方法區中,而後在堆區中實例化一個java.lang.Class對象,做爲方法區中這個類的信息的入口。java

       類的加載方式比較靈活,咱們最經常使用的加載方式有兩種,一種是根據類的全路徑名找到相應的class文件,而後從class文件中讀取文件內容;另外一種是從jar文件中讀取。另外,還有下面幾種方式也比較經常使用:設計模式

  • 從網絡中獲取:好比10年前十分流行的Applet。網絡

  • 根據必定的規則實時生成,好比設計模式中的動態代理模式,就是根據相應的類自動生成它的代理類。jvm

  • 從非class文件中獲取,其實這與直接從class文件中獲取的方式本質上是同樣的,這些非class文件在jvm中運行以前會被轉換爲可被jvm所識別的字節碼文件。spa

       對於加載的時機,各個虛擬機的作法並不同,可是有一個原則,就是當jvm「預期」到一個類將要被使用時,就會在使用它以前對這個類進行加載。好比說,在 一段代碼中出現了一個類的名字,jvm在執行這段代碼以前並不能肯定這個類是否會被使用到,因而,有些jvm會在執行前就加載這個類,而有些則在真正須要 用的時候纔會去加載它,這取決於具體的jvm實現。咱們經常使用的hotspot虛擬機是採用的後者,就是說當真正用到一個類的時候纔對它進行加載。設計

       加載階段是類的生命週期中的第一個階段,加載階段以後,是鏈接階段。有一點須要注意,就是有時鏈接階段並不會等加載階段徹底完成以後纔開始,而是交叉進 行,可能一個類只加載了一部分以後,鏈接階段就已經開始了。可是這兩個階段總的開始時間和完成時間老是固定的:加載階段老是在鏈接階段以前開始,鏈接階段 老是在加載階段完成以後完成。代理

 

鏈接

       鏈接階段比較複雜,通常會跟加載階段和初始化階段交叉進行,這個階段的主要任務就是作一些加載後的驗證工做以及一些初始化前的準備工做,能夠細分爲三個步驟:驗證、準備和解析。對象

  1. 驗證:當一個類被加載以後,必需要驗證一下這個類是否合法,好比這個類是否是符合字節碼的格式、變量與方法是否是有重複、數據類型是否是有效、繼承與實現是否合乎標準等等。總之,這個階段的目的就是保證加載的類是可以被jvm所運行。
    繼承

  2. 準備:準備階段的工做就是爲類的靜態變量分配內存並設爲jvm默認的初值,對於非靜態的變量,則不會爲它們分配內存。有一點須要注意,這時候,靜態變量的初值爲jvm默認的初值,而不是咱們在程序中設定的初值。jvm默認的初值是這樣的:接口

    • 基本類型(int、long、short、char、byte、boolean、float、double)的默認值爲0。

    • 引用類型的默認值爲null。

    • 常量的默認值爲咱們程序中設定的值,好比咱們在程序中定義final static int a = 100,則準備階段中a的初值就是100。

  3.  解析:這一階段的任務就是把常量池中的符號引用轉換爲直接引用。那麼什麼是符號引用,什麼又是直 接引用呢?咱們來舉個例子:咱們要找一我的,咱們現有的信息是這我的的身份證號是1234567890。只有這個信息咱們顯然找不到這我的,可是經過公安 局的身份系統,咱們輸入1234567890這個號以後,就會獲得它的所有信息:好比安徽省黃山市餘暇村18號張三,經過這個信息咱們就能找到這我的了。 這裏,123456790就比如是一個符號引用,而安徽省黃山市餘暇村18號張三就是直接引用。在內存中也是同樣,好比咱們要在內存中找一個類裏面的一個 叫作show的方法,顯然是找不到。可是在解析階段,jvm就會把show這個名字轉換爲指向方法區的的一塊內存地址,好比c17164,經過 c17164就能夠找到show這個方法具體分配在內存的哪個區域了。這裏show就是符號引用,而c17164就是直接引用。在解析階段,jvm會將 全部的類或接口名、字段名、方法名轉換爲具體的內存地址。

        鏈接階段完成以後會根據使用的狀況(直接引用仍是被動引用)來選擇是否對類進行初始化。

 

初始化

       若是一個類被直接引用,就會觸發類的初始化。在java中,直接引用的狀況有:

  • 經過new關鍵字實例化對象、讀取或設置類的靜態變量、調用類的靜態方法。

  • 經過反射方式執行以上三種行爲。

  • 初始化子類的時候,會觸發父類的初始化。

  • 做爲程序入口直接運行時(也就是直接調用main方法)。

相關文章
相關標籤/搜索