2016-02-02 62 views
24

我寫了下面的代碼併爲超類創建了對象。爲什麼子類的靜態代碼得到執行?

class SuperClass{ 
    static int a=2; 
    static int b(){ 
     return 2; 
    } 
    int c(){ 
     return 2; 
    } 

    SuperClass(){ 
     System.out.println("Super"); 
    } 
    static { 
     System.out.println("super"); 
    } 
} 

public class Sub extends SuperClass{ 
    Sub(){ 
    System.out.println("Sub"); 
    } 
    static { 
     System.out.println("sub"); 
    } 
    static int b(){ 
     return 3; 
    } 
    int c(){ 
     return 3; 
    } 
    public static void main(String ax[]){ 
     SuperClass f =new SuperClass(); 
     System.out.println(f.c()); 
     System.out.print(SuperClass.b()); 
    } 
} 

當我檢查了輸出,則如下:

super 
sub 
Super 
2 
2 

我知道,當類對象初始化或任何靜態參考由靜塊時,纔會執行。但是在這裏,我沒有把這些東西交給Sub類。那麼爲什麼我會看到「sub」即子類的靜態塊輸出?

+11

執行'main'方法(嵌套在'Sub'類中)是一個靜態引用。 :) –

+0

@KonstantinYovkov我想過,但即使如此,「子」應該是第一個正確的。現在,這個疑問從Bathsheba的答案中清除了,因爲靜態塊按照超類和子類的順序執行。謝謝。 – AV94

+3

@anil首先,'Sub'類仍然依賴於'Super'類,因此它首先被執行。 – njzk2

回答

37

我知道只有當類的對象被初始化或任何靜態引用時才執行靜態塊。但是在這裏,我沒有把這些東西交給Sub類。

代碼不對,但爲了爲main運行,Sub必須加載。所以它的靜態初始化器就運行了。

例如,我假設你運行它像這樣:

java Sub 

java工具必須加載Sub調用Sub.main。這是導致靜態初始化器運行的靜態引用(真正的訪問)。 (如果您在IDE中運行它,IDE將執行java工具部件,但結果是相同的。)

因此,這裏發生了什麼事:

  1. java爲了觸發Sub

  2. JVM具有加載SuperClass負荷加載Sub

  3. 所以我們看到它們的靜態初始化運行, (SuperClass,然後Sub):

    super 
    sub 
    
  4. java工具調用main

  5. 守則main電話new SuperClass

    Super 
    
  6. 守則main電話f.c()

    2 
    
  7. main個呼叫SuperClass.b

    2 
    

作爲Holger有益points out,這是通過JVM規範中§5.5 - Initialization覆蓋,並且相關§5.2 - Java Virtual Machine Startup

一類的初始化或接口包括執行其類或接口初始化方法(§2.9)。

類或接口C可以被初始化僅作爲結果:

  • ...

  • 如果C是一類,它的子類中的一個的初始化。

  • 如果C是一個類,它的名稱作爲Java虛擬機啓動(§5.2)中的初始類。

這第二個到最後的子彈對焦點覆蓋SuperClass,最後的子彈點覆蓋Sub

12

由於您的main()方法是Sub的成員,因此需要爲您的程序加載該類才能運行。

9

在調用main時,首先調用所有靜態初始化器,首先在超類中調用,然後調用子類。

這解釋了您觀察到的輸出。

3

靜態塊在加載類時運行。通常是因爲你調用了構造函數或靜態成員。在這種情況下,這是因爲你執行了主要方法(一個靜態成員)。

側筆記:

  1. 另一邊緣情況下調用的Class.forName(類名)加載的類。
  2. 您可能還注意到,基類是在子類之前加載的。