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繼承的靜態初始化
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繼承的靜態初始化
的參考B.x
問題下面的字節碼:
getstatic #3 <Field int B.x>
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
類需要加載。
Class B
延伸A
它有一個public static variable x
,當你調用B.x
如果你希望Inside B.
作爲了就把你必須創建一個類的對象,你正在訪問。所有的靜態代碼塊都被執行。或者將該靜態代碼塊移動到類A
:-)
當JVM加載類時,它會將所有靜態塊組合起來,並按它們聲明的順序執行它們。
編輯(Source): 簡短的回答是靜態不是存在於Java繼承。相反,在類中聲明的靜態成員是(受到「訪問」限制的)直接在派生類的名稱空間中可見,除非它們被派生類中的聲明「隱藏」。
因此,如果靜態屬於該類只爲什麼它滴落到 派生類?難道它不應該只與定義爲 的類保持一致嗎?
是的,但爲什麼靜態塊不執行。 –
您不必創建該類的對象來執行靜態塊。見下面 – durron597
@ durron597我只是告訴一個方式來實現任何方式的問題,我的例子是爲什麼例子中沒有執行靜態代碼塊在派生類中:-) –
因爲B.x
實際上是A.x
所以只有A
類需要被加載。
它實際上並不需要加載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將所有這些塊組合成一個靜態塊,然後執行。 「
所以這看起來像編譯器優化,但編譯器可以不同。它在某處被描述了嗎? –
@ user1839039:我爲您添加了一個鏈接 – durron597
初始化類的包括執行其
static
初始化和初始化在類中聲明靜態字段(類變量)。[&hellip;]
到
static
字段的引用(§8.3.1.1)僅使類或實際聲明它接口初始化時,即使它可能通過一個子類,子接口的名稱被稱爲或者實現接口的類。
因此,儘管—違背權利要求一些上述B
—類的答案也必須加載,以確定B.x
在A
聲明,類B
不初始化(即它的static
初始值設定項實際上沒有運行),直到你做了一些更具體的B
。
好,但它的行爲描述,我的意思是規範呢? –
這不是真的。例如,您可以將靜態字段'x'添加到'B',即使您不重新編譯'Main',它也會被打印。 – axtavt
@axtavt你是對的。我改變了一下我的答案。 – ShyJ