歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java初始化過程

Java初始化過程

日期:2017/3/1 9:06:46   编辑:Linux編程

這篇文章主要講解Java在創建對象的時候,初始化的順序。主要從以下幾個例子中講解:

  • 繼承關系中初始化順序
  • 初始化塊與構造器的順序
  • 已經加載過的類的初始化順序
  • 加載父類,會不會加載子類
  • 創建子類對象會不會創建父類對象

例子1——繼承關系中初始化順序

先看簡單的情況,看下面的例子:

public class Father {

    public String fatherVar = "父類構造塊初始化";
    public static int fatherStaticVar;
    public int i;
    static {
        int i = 100;
        System.out.println("父類靜態塊初始化,i的值為" + i);
        System.out.println("父類靜態變量初始化,fatherStaticVar的值為" + fatherStaticVar);
    }

    {
        System.out.println(fatherVar);
    }

    public Father(){
        System.out.println("父類構造函數的初始化,i的值" + i);
    }
}

public class Son extends Father {

    public String sonVar = "子類構造塊初始化";
    public static int sonStaticVar;
    public int i;
    static {
        int i = 101;
        System.out.println("子類靜態塊初始化,i的值為" + i);
        System.out.println("子類靜態變量初始化,sonStaticVar的值為" + sonStaticVar);
    }

    {
        System.out.println(sonVar);
    }

    public Son(){
        super();
        System.out.println("子類構造函數的初始化,i的值" + i);
    }

    public static void main(String[] args) {
        new Son();
    }
}

其執行的結果如下:

父類靜態塊初始化,i的值為100
父類靜態變量初始化,fatherStaticVar的值為0
子類靜態塊初始化,i的值為101
子類靜態變量初始化,sonStaticVar的值為0
父類構造塊初始化
父類構造函數的初始化,i的值0
子類構造塊初始化
子類構造函數的初始化,i的值0

按照結果,我們可以知道在有繼承的時候,雖然是創建一個Son對象,但是JVM發現Son對象的類還沒有裝載,而Son類又繼承自Father類,只有加載了Father類,才能加載Son類。於是加載Father類的時候,就會初始化一切靜態變量和靜態塊。所以上文結果中第一行和第二行是父類靜態變量和靜態塊初始化的結果,然後加載完Father類之後,又會加載Son類,同樣是初始化Son類的靜態塊和靜態變量,出現上文中第三行和第四行的結果。等這個2個類都加載完了,才開始創建Son對象,因為Son對象,顯示調用了Father類的構造器,所以先執行Father類的構造器,出現第五行和第六行的結果,等Father類構造器執行完了,才執行後續Son構造器的內容,所以最後出現了第七行和第八行的結果。

例子2——初始化塊與構造器的順序

在上面的例子中,有2個語句塊叫初始化塊。在上文的結果中是初始化塊的執行是先於構造器的,現在看一下把初始化塊的內容放到構造器下面,會是什麼的結果

public class InitBlock {

    public InitBlock(){
        System.out.println("構造器在執行......");
    }

    {
        System.out.println("初始化塊1在執行......");
    }

    {
        System.out.println("初始化塊2在執行......");
    }

    public static void main(String[] args) {
        new InitBlock();
    }
}

結果如下:

初始化塊1在執行......
初始化塊2在執行......
構造器在執行......

很顯然,無論初始化塊寫在哪個地方,都是先於構造器執行的,但是初始化塊之間的順序是前面的先初始化,後面在初始化。

例子3——已經加載過的類的初始化順序

更改一下例子1中的main方法,改成如下:

public static void main(String[] args) {
        new Father();
        System.out.println("=============");
        new Son();
    }

結果如下:

父類靜態塊初始化,i的值為100
父類靜態變量初始化,fatherStaticVar的值為0
子類靜態塊初始化,i的值為101
子類靜態變量初始化,sonStaticVar的值為0
父類構造塊初始化
父類構造函數的初始化,i的值0
=============
父類構造塊初始化
父類構造函數的初始化,i的值0
子類構造塊初始化
子類構造函數的初始化,i的值0

結果很有意思,創建父類對象的時候,加載Father類,出現第一行和第二行的結果,但是這個竟然會還把子類的靜態變量和靜態塊初始化?這個原因,例子4在說。 最後執行父類的構造器創建父類對象。當再創建子類的時候,發現父類和子類已經加載過了,所以不會再加載Father和Son類,只會調用父類的構造器,再執行後續子類構造器的內容,創建子類。

例子4——加載父類,會不會加載子類

用一個嶄新的例子來看看上面,創建父類的時候,為什麼會打印出子類靜態初始化執行的結果。

public class StaticFather {
    static{
        System.out.println("父類靜態初始化塊");
    }
}

public class StaticSon extends StaticFather{
    static {
        System.out.println("子類靜態初始化塊");
    }
}

public class Test {

    public static void main(String[] args) {
        new StaticFather();
    }
}

結果如下:

父類靜態初始化塊

這次就不會創建父類的時候,加載子類。例子3之所以出現這個原因 是因為main函數在子類中寫的,要執行main函數必須要加載子類。只會加載子類之前要先加載父類,因為不加載父類,只加載子類,怎麼讓子類調用父類的方法和變量。但是加載父類不會加載子類,反正父類也調用不了子類的方法。

例子5——創建子類對象會不會創建父類對象

做個實驗,看一下創建子類對象的���候,到底會不會創建一個父類對象,先說結論:不會。從道理上講,如果創建任何一個對象都要創建出一個他的父類對象的話,那麼整個JVM虛擬機都是Object對象。看下面的實驗:

public class ObjectFather {

    public void getInfo(){
        System.out.println(getClass().toString());
    }
}

public class ObjectSon extends ObjectFather{

    public ObjectSon(){
        super();
        super.getInfo();
    }

    public static void main(String[] args) {
        new ObjectSon();
    }
}

結果如下:

class com.byhieg.init.ObjectSon

可以看出來,創建子類對象時那個父類的Class還是子類的,也就是說創建子類對象並沒有創建一個父類的對象,只是說調用了父類的構造器,對父類的屬性進行初始化,並且給子類提供了一個super指示器去調用父類中那些變量和方法。
更詳細的說,new一個對象實際上是通過一個new指令開辟一個空間,來存放對象。在new ObjectSon()的時候,就只有一個new指令,只會開辟一個空間,所謂初始化父類等等,都是在這個空間中有一個特殊的區域來存放這些數據,而super關鍵字就是提供了訪問這個特殊區域的方法,通過super去訪問這個特殊區域。
還可以比較super和this的hashcode來判斷,結果必然是兩者的hashcode是一致的。

總結

至此,Java初始化的講解到結束了,基本了覆蓋了絕大多數情況中的初始化。

Copyright © Linux教程網 All Rights Reserved