《深入理解java虛擬機器》:類的初始化

來源:互聯網
上載者:User

標籤:java虛擬機器   類的初始化   

深入理解java虛擬機器》:類的初始化

類從被載入到虛擬機器記憶體中開始,到卸載出記憶體為止,它的整個生命週期包括:載入、驗證、準備、解析、初始化、使用和卸載七個階段。其中驗證、準備、解析3個部分統稱為串連。類載入的過程包括了載入、驗證、準備、解析、初始化五個階段。

載入、驗證、準備、初始化和卸載這5個階段的順序時確定的,類的載入過程必須按照這種順序按部就班的開始,而解析階段則不一定,它在某些情況下可以在初始化階段之後開始,這是為了支援Java語言的運行時綁定(也成為動態綁定或晚期綁定)。另外注意這裡的幾個階段是按順序開始,而不是按順序進行或完成,因為這些階段通常都是互相交叉地混合進行的,通常在一個階段執行的過程中調用或啟用另一個階段。

類初始化是類載入過程的最後一個階段,到初始化階段,才真正開始執行類中的Java程式碼。虛擬機器規範嚴格規定了有且只有5種情況必須立即對類進行初始化:

  • 第一種:遇到new、getstatic、putstatic、invokestatic這四條位元組碼指令時,如果類還沒有進行過初始化,則需要先觸發其初始化。產生這四條指令最常見的Java代碼情境是:使用new關鍵字執行個體化對象時、讀取或設定一個類的靜態欄位(static)時(被static修飾又被final修飾的,已在編譯期把結果放入常量池的靜態欄位除外)、以及調用一個類的靜態方法時。
  • 第二種:使用Java.lang.refect包的方法對類進行反射調用時,如果類還沒有進行過初始化,則需要先觸發其初始化。
  • 第三種:當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化。
  • 第四種:當虛擬機器啟動時,使用者需要指定一個要執行的主類,虛擬機器會先執行該主類。
  • 第五種:當使用JDK1.5支援時,如果一個java.langl.incoke.MethodHandle執行個體最後的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法控制代碼,並且這個方法控制代碼所對應的類沒有進行過初始化,則需要先觸發其初始化。

虛擬機器規定有且只有這5種情況才會觸發類的初始化,這5中情境中的行為稱為對一個類進行主動引用,除此之外所有引用類的方式都不會觸發其初始化,稱為被動引用。下面舉一些例子來說明被動引用。

1、通過子類引用父類中的靜態欄位,這時對子類的引用為被動引用,因此不會初始化子類,只會初始化父類
package org.wrh.classupload;/* * 通過子類引用父類的靜態欄位,不會導致子類初始化 * */public class TestClassDemo01 {    public static void main(String[] args) {        // TODO Auto-generated method stub        System.out.println(SubClass.i);//子類引用父類的靜態欄位    }}class SuperClass{    public static int i=3;//父類的static欄位    static{//當此類在虛擬機器中初始化的時候,此static塊將會被執行        System.out.println("SuperClass  init");    }}class SubClass extends SuperClass{    static{//當此類在虛擬機器中初始化的時候,此static塊將會被執行        System.out.println("SubClass init");    }}

程式運行結果如下:

SuperClass init
3

即只輸出了“SuperClass init”,而沒有輸出“SubClass init”。

結論:對於靜態欄位,只有直接定義這個欄位的類才會被初始化,因此通過其子類來引用父類中定義的靜態欄位,只會觸發父類的初始化而不會觸發子類的初始化。至於是否要觸發子類的載入和驗證,在虛擬機器規範中並未明確規定,這點取決於虛擬機器的具體實現。

使用new執行個體化對象時,會先把父類初始化,然後再初始化此類本身
package org.wrh.classupload;/* * 通過子類引用父類的靜態欄位,不會導致子類初始化 * */public class TestClassDemo01 {    public static void main(String[] args) {        //System.out.println(SubClass.i);        //SuperClass s=new SuperClass();        SubClass s=new SubClass();    }}class SuperClass{    public static int i=3;    static{        System.out.println("SuperClass  init");    }}class SubClass extends SuperClass{    static{        System.out.println("SubClass init");    }}

運行結果如下:

SuperClass init
SubClass init

通過數組定義來引用類,不會觸發此類的初始化
package org.wrh.classupload;public class TestClassDemo02 {    public static void main(String[] args) {        // TODO Auto-generated method stub        SuperClass_1 superClass[]=new SuperClass_1[5];    }}class SuperClass_1{    static{        System.out.println("SuperClass init");    }}

執行後沒有輸出任意內容,說明沒有進行任何類的初始化工作。

但是,但這段代碼裡觸發了另一個名為“LLSuperClass_1”的類的初始化,它是一個由虛擬機器自動產生的、直接繼承於java.lang.Object的子類,建立動作由位元組碼指令newarray觸發,很明顯,這是一個對數組參考型別的初始化。

常量在編譯階段會存入調用它的類的常量池中,本質上沒有直接引用到定義該常量的類,因此不會觸發定義常量的類的初始化
package org.wrh.classupload;public class NotInitialization {    public static void main(String[] args) {        System.out.println(ConstClass.VALUE);    }}class ConstClass{    public static final int VALUE=3;    static{        System.out.println("ConstClass init");    }}

運行結果如下:

3

沒有輸出“ConstClass init”,因此可以得到當我們引用final修飾的常量時此類並沒有初始化。
雖然程式中引用了ConstClass類的常量VALUE,但是在編譯階段將此常量的值“3”儲存到了調用它的類ConstClass的常量池中,對常量Const.VALUE的引用實際上轉化為了ConstClass類對自身常量池的引用。也就是說,實際上ConstClass的Class檔案之中並沒有Const類的符號引用入口,這兩個類在編譯成Class檔案後就不存在任何聯絡了。

介面的載入過程

介面的載入過程與類載入過程稍微有點不同,針對介面需要做一些特殊的說明:介面也有初始化過程,這點與類是一致的,上面的代碼都是用靜態語句塊”static{}“來輸出初始化資訊的,而介面中不能使用”static{}“語句塊,但是編譯器仍然會為介面產生”()”類構造器,用於初始化介面中所定義的成員變數。介面與類真正有所區別的是前面講述的5種“有且只有”需要開始初始化情境中的第三種:當一個類在初始化時,要求其父類全部都已經初始化過了,但是在介面在初始化的時候,並不要求其父介面都完成了初始化,只要在真正使用到父介面的時候(如引用介面中定義的常量)才會初始化

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

《深入理解java虛擬機器》:類的初始化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.