2016-08-03 59 views
1

在下面的Java代碼中,Insect類由Beetle類繼承。Java - 此代碼中初始化的順序是什麼?

class Insect { 

    private int i = 9; 
    protected int j; 

    Insect() { 
     System.out.println("i = " + i + ", j = " + j); 
     j = 39; 
    } 
    private static int x1 
      = printInit("static Insect.x1 initialized"); 

    static int printInit(String s) { 

     System.out.println(s); 
     return 47; 
    } 
} 

public class Beetle extends Insect { 

    private int k = printInit("Beetle.k initialized"); 

    public Beetle() { 
     System.out.println("k = " + k); 
     System.out.println("j = " + j); 
    } 
    private static int x2 
      = printInit("static Beetle.x2 initialized"); 

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

輸出以某種方式混淆。

靜態Insect.x1初始化

靜態Beetle.x2初始化

甲殼蟲構造

I = 9,J = 0

Beetle.k初始化

ķ = 47 j = 39

在這個特定的例子中初始化的順序是什麼?

爲什麼在x1之後立即初始化x2?爲什麼主要方法的第一行(System.out.println("Beetle constructor");),在 x1和x2 intializaton之後執行。所以令人滿意。

我知道派生類構造函數會自動調用基類構造函數(除非它有參數並且使用super關鍵字)。我知道變量在構造函數之前被初始化,並且靜態變量在其他變量之前被初始化。

回答

4

x1x2是靜態的。這意味着它們在加載類時被初始化。由於主要方法在Beetle中,因此必須在調用main之前加載該類。這就是爲什麼x1x2初始化是你看到的第一個東西。不知道爲什麼這兩個的順序是這樣的。

現在您撥打main並執行System.out.println("Beetle constructor");。然後它呼叫Beetle(),其首先隱含地稱爲super()(又名Insect())。這將打印i = 9, j = 0因爲i是9和j沒有在這一點上,這意味着它有0

現在j設置爲39和流量繼續Beetle()默認int值被初始化。這現在初始化Beetle的字段,在你的情況下爲k。所以當涉及到Beetle()中的顯式代碼時,k被超級構造函數初始化爲47和j到39。

+0

所以我可以說,作爲一般規則,即: 1.基類的靜態成員首先初始化, 2.在派生類靜態成員初始化接下來, 3.基類的非靜態成員(原語和引用)被初始化 4.基類構造函數被調用 5.派生類非靜態成員被初始化 6.最後,我有我需要的一切來創建對象,所以派生類構造函數被調用。 對嗎? –

+1

@HelloLili在這個簡單的情況下是的,但我會小心使用它作爲一般規則。 Java按Java語言規範中定義的一組規則工作。我認爲你最好學習如何觸發某些行動。請記住,「加載一個類會觸發其靜態成員的初始化」,而不是「靜態成員優先」等等。 –

2

這可以作如下解釋 -

由於靜態成員是非實例成員即僅構件的一個副本跨類的所有實例共享,這些部件被第一初始化。

在這種情況下,x1首先被初始化,因爲它存在於存在main方法的類的基類中的靜態成員。

因此,第1個x1初始化爲

子類中的靜態成員x2由於相同的原因,也因爲在昆蟲類中不存在其他靜態成員。

甲殼蟲構造函數行是從主要方法打印。

超類和子類的構造函數的調用一個接一個顯而易見的原因

2

JVM(類加載)加載甲殼蟲類,當你調用它的主要的靜態方法。在類加載之後,Beetle類的初始化發生,這意味着初始化類的所有靜態成員。

基類始終隱式初始化,因此您會看到在x2之前初始化的x1。

您看到x1和x2之後打印的「Beetle構造函數」,因爲當您引用某個類的靜態方法時(如通過調用main所做的那樣),JVM執行順序跳轉到初始化類靜態成員,然後繼續執行main()方法。

作爲一個實驗,嘗試刪除的主要方法到另一個類,

public class Beetle1 { 
public static void main(String[] args) { 
     System.out.println("Beetle1 constructor"); 
    } 
} 

現在作爲甲殼蟲的構造不被引用,類加載器不會加載它,你會看到Beetle1構造打印。