2014-04-01 52 views
3

代碼:如何JVM加載父類中的Java

class A { 
    static { 
     System.out.println("loading A static 1"); 
    } 
    static { 
     System.out.println("loading A static 2 B.c= "+B.c);   
    } 
    static { 
     System.out.println("loading static 3"); 
    } 
    static int a=10; 
    A(){   
    } 
} 

class B extends A{ 
    static { 
     System.out.println("loading B A.a= "+A.a); 
    } 
    static int c = 50; 
} 
public class Test { 
    public static void main(String[] args) { 
     new B(); 
    } 
} 

輸出:

loading A static 1 
loading A static 2 B.c= 0 
loading static 3 
loading B A.a= 10 

從這出去放我們可以說,子類,但孩子下課後父類加載後初始化父母班? 如果是的話JVM如何加載類層次結構?

回答

3

您可以通過java -verbose Test執行它檢查:

... 
[Loaded A from file:/.../src/main/java/] 
[Loaded B from file:/.../src/main/java/] 
loading A static 1 
loading A static 2 B.c= 0 
loading static 3 
loading B A.a= 10 
... 

所以,不,父類加載第一了。

+0

那麼爲什麼在輸出的第二行給出B.c = 0如果B類未加載如何B.c = 0來了?謝謝你 –

+0

在這一點上,這兩個類都加載,你可以從輸出中看到。 'B.c'尚未初始化,所以它仍然是'0'。我認爲輸出顯示的東西的順序非常清楚。 – Keppil

+0

哦,明白了:)謝謝,能否告訴我JVM如何知道類的層次結構? –

1

當一個類被初始化時,靜態塊將被執行。我們知道

類初始化之前,它的直接超類必須初始化,

你的情況

所以,當你初始化它的超類之前自動初始化B中。

的詳細信息,您可以檢查this part of spec

5

Java語言規範explains初始化類的過程。

類或接口類型T將緊接在以下中的任何一個的第一 發生之前被初始化:

  • T是一個類並且創建T的實例。

  • T是一個類,由T聲明的靜態方法被調用。

  • 指定由T聲明的靜態字段。

  • 使用由T聲明的靜態字段,該字段不是常量變量(§4.12.4)。

  • T是一個頂級類(§7.6),並執行了一個在T(§8.1.3)中在詞彙上嵌套的斷言語句(§14.10)。

with more details

[...]

同步在初始化鎖,LC,爲C.這涉及 等到當前線程才能獲取LC。

[...]

如果C的Class對象指示當前線程正在對C進行初始化 ,那麼這必須是對 初始化的遞歸請求。釋放LC並正常完成。

[...]

接着,如果C是一個類而不是一個接口,並且它的超類SC 尚未初始化,然後遞歸用於SC執行此整個 過程。如有必要,請先驗證並準備SC。如果SC的 初始化由於拋出的異常而突然完成,則 然後獲取LC,將Class對象標記爲C爲錯誤,通知所有 等待線程,釋放LC並突然完成,拋出與初始化相同的 異常SC。

所以

new B(); 

要求類B被初始化。因爲BA的子類,所以需要初始化A。當初始化A,該

static { 
    System.out.println("loading A static 2 B.c= "+B.c);   
} 

表明B需要被初始化,但B已經處於被初始化的過程,所以它會被忽略,現在和A初始化繼續進行。 由於B的初始化未完成,因此c字段尚未初始化爲50,因此它會打印0

A初始化完成。 B繼續初始化。 B初始化完成和Boom!你完成了。