2012-11-20 146 views
13
 
    public class Main { 

     public static void main(String[] args) { 
      System.out.println(B.x); 
     } 

    } 
    class A { 
     public static String x = "x"; 
    } 
    class B extends A { 
     static { 
      System.out.print("Inside B."); 
     } 
    } 

問題:爲什麼輸出將是:「x」。但不是:「內部B.x」java繼承的靜態初始化

回答

9

的參考B.x問題下面的字節碼:

getstatic  #3 <Field int B.x> 

根據Java Virtual Machine Spec

Java虛擬機指令anewarray,checkcast,getfield命令, getstatic,的instanceof,invokedynamic,invokeinterface ,invokespecial, invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new, put字段,並putstatic使符號引用運行時 常量池。執行任何這些指令需要 分辨率的符號參考

所以JVM應該可以解決符號引用B.x。領域分辨率爲specified like this

要在 類或C接口解析爲一個場從d未解決的符號引用時,符號引用到C由場 參考給定必須首先被解析(第5.4節。 3.1)。

...

在解決一個字段引用,場分辨率首先嚐試 查找的基準場C和其超

。如果C聲明一個字段由 區域基準指定的名稱和描述,字段查找成功。聲明的字段是字段查找的結果 。

否則,查找字段遞歸地應用於指定類或接口C的直接 超接口

否則,如果C有一個超類S,場查找施加 遞歸到S.

否則,字段查找失敗。

換句話說,JVM會將B.x分解爲A.x。這就是爲什麼只有A類需要加載。

+0

好,但它的行爲描述,我的意思是規範呢? –

+0

這不是真的。例如,您可以將靜態字段'x'添加到'B',即使您不重新編譯'Main',它也會被打印。 – axtavt

+0

@axtavt你是對的。我改變了一下我的答案。 – ShyJ

2

Class B延伸A它有一個public static variable x,當你調用B.x

如果你希望Inside B.作爲了就把你必須創建一個類的對象,你正在訪問。所有的靜態代碼塊都被執行。或者將該靜態代碼塊移動到類A :-)

當JVM加載類時,它會將所有靜態塊組合起來,並按它們聲明的順序執行它們。

編輯Source): 簡短的回答是靜態不是存在於Java繼承。相反,在類中聲明的靜態成員是(受到「訪問」限制的)直接在派生類的名稱空間中可見,除非它們被派生類中的聲明「隱藏」。

因此,如果靜態屬於該類只爲什麼它滴落到 派生類?難道它不應該只與定義爲 的類保持一致嗎?

+0

是的,但爲什麼靜態塊不執行。 –

+0

您不必創建該類的對象來執行靜態塊。見下面 – durron597

+0

@ durron597我只是告訴一個方式來實現任何方式的問題,我的例子是爲什麼例子中沒有執行靜態代碼塊在派生類中:-) –

6

因爲B.x實際上是A.x所以只有A類需要被加載。

2

它實際上並不需要加載B,直到它直接訪問B的靜態成員。請注意,此代碼:

public class TestMain { 
    public static void main(String[] args) { 
     System.out.println(B.x); 
     System.out.println(B.y); 
    } 

    static class A { 
     public static String x = "x"; 
    } 

    static class B extends A { 
     public static String y = "y"; 
     static { 
      System.out.print("Inside B."); 
     } 
    } 
} 

將輸出:

x 
Inside B.y 

因爲它不需要加載B直到東西B被訪問。

Here's a good link on the subject.從文章中,「不要忘記,這些代碼將在JVM加載類時執行,JVM將所有這些塊組合成一個靜態塊,然後執行。 「

+0

所以這看起來像編譯器優化,但編譯器可以不同。它在某處被描述了嗎? –

+0

@ user1839039:我爲您添加了一個鏈接 – durron597

3

§12.4 "Initialization of Classes and Interfaces" of The Java Language Specification, Java SE 7 Edition規定:

初始化類的包括執行其static初始化和初始化在類中聲明靜態字段(類變量)。

[&hellip;]

static字段的引用(§8.3.1.1)僅使類或實際聲明它接口初始化時,即使它可能通過一個子類,子接口的名稱被稱爲或者實現接口的類。

因此,儘管—違背權利要求一些上述B —類的答案也必須加載,以確定B.xA聲明,類B初始化(即它的static初始值設定項實際上沒有運行),直到你做了一些更具體的B