JVM中java類的加載時機

scjscj0220 8年前發布 | 8K 次閱讀 Java開發

來自: http://blog.csdn.net//chenleixing/article/details/47099725


Java虛擬機把描述類的數據從Class文件加載到內存,并對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的加載機制。
類從被加載到虛擬機內存中開始,到卸載出內存為止,它的整個生命周期包括了:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸載(Unloading)七個階段。其中驗證、準備和解析三個部分統稱為連接(Linking),如下如所示。


這七個階段,加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類的加載過程必須按照這個順序來按部就班地開始,而解析階段則不一定,它在某些情況下可以在初始化階段后再開始。

類的生命周期的每一個階段通常都是互相交叉混合式進行的,通常會在一個階段執行的過程中調用或激活另外一個階段。
Java虛擬機規范沒有強制性約束在什么時候開始類加載過程,但是對于初始化階段,虛擬機規范則嚴格規定了有且只有四種情況必需立即對類進行“初始化”(而加載、驗證、準備階段則必需在此之前開始),這四種情況歸類如下:

1.遇到new、getstatic、putstatic或invokestatic這4條字節碼指令時,如果類沒有進行過初始化,則需要先觸發其初始化。生成這4條指令最常見的Java代碼場景是:使用new關鍵字實例化對象時、讀取或者設置一個類的靜態字段(被final修飾、已在編譯器把結果放入常量池的靜態字段除外)時、以及調用一個類的靜態方法的時候。
2.使用java.lang.reflect包的方法對類進行反射調用的時候,如果類沒有進行過初始化,則需要先觸發其初始化。
3.當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要觸發父類的初始化。
4.當虛擬機啟動時,用戶需要指定一個執行的主類(包含main()方法的類),虛擬機會先初始化這個類。
對于這四種觸發類進行初始化的場景,在java虛擬機規范中限定了“有且只有”這四種場景會觸發。這四種場景的行為稱為對類的主動引用,除此以外的所有引用類的方式都不會觸發類的初始化,稱為被動引用。

下面通過三個實例來說明被動引用:

示例1:

父類SuperClass.java 
public class SuperClass {  
    static{  
         System.out.println("SuperClass init!");  
      }  
     public static int value = 123;  
}  
子類SubClass.java
     public class SubClass extends SuperClass {  
     static{  
        System.out.println("SubClass init!");  
    }  
}  

主類NotInitialization.java
public class NotInitialization {  
    public static void main(String[] args) {  
        System.out.println(SubClass.value);  
    }  
}
輸出結果:

SuperClass init! 

123


由結果可以看出只輸出了“SuperClass init!”,沒有輸出“SubClass init!”。這是因為對于靜態字段,只有直接定義該字段的類才會被初始化,因此當我們通過子類來引用父類中定義的靜態字段時,只會觸發父類的初始化,而不會觸發子類的初始化。

示例2:

SuperClass[ ]   scs=new SuperClass[11];


如上,當初始化一個對象數組的時候,也不會觸發類的初始化。

示例3:

public class ConstClass {

   static {

    system.out.printl("const");

}

   public static final int age =123;  

}

public class NotInitialization{

     public static void main(String[ ] args){

     system.out.println(ConstClass.age);

}

此時并不會出現 “const”,因為在NotInitialization類在編譯的時候已經把ConstClass中的變量age放在常量池中了,訪問時直接取出age即可,不會引發ConstClass的初始化。

 

 

 本文由用戶 scjscj0220 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!