2013-04-12 123 views
1

我有如下場景 package com.example.test;執行順序,靜態塊

public class StaticTest { 

    public static final String STATIC_VAR="Static Var"; 

    static{ 
     System.out.println("Static Block Called...."); 
    } 
public static void init(){} 
} 

package com.example.test; 

public class MainClass { 
    public static void main(String[] args) { 
     System.out.println("Test static initialization"); 
     String staticvar =StaticTest.STATIC_VAR; 
     System.out.println("Referred static variable--> "+ staticvar); 
     System.out.println("Calling static method"); 
     StaticTest.init(); 
     System.out.println("Static method invoked"); 
    } 

} 

我得到的輸出是

Test static initialization 
Referred static variable--> Static Var 
Calling static method 
**Static Block Called....** 
Static method invoked 

和輸出我所期待的是

Test static initialization 
**Static Block Called....** 
Referred static variable--> Static Var 
Calling static method 
Static method invoked 

我想,只要我指靜態變量靜態塊將得到執行。

有什麼解釋?

+1

請參閱[Java靜態類初始化](http://stackoverflow.com/questions/3499214/java-static-class-initialization)和[靜態塊和靜態變量在一個類中執行的順序是什麼?](http ://stackoverflow.com/questions/12448465/in-what-order-are-static-blocks-and-static-variables-in-a-class-executed)。 –

回答

0

主要原因是您將STATIC_VAR聲明爲常量值,該值將由編譯器內聯,而不是被引用。將代碼更改爲

public static /*final*/ String STATIC_VAR="Static Var"; 

並且您將獲得您期望的行爲。

參見Java語言規範的§12.4.1. When Initialization Occurs

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

  • ...
  • 使用由T聲明的靜態字段,該字段爲而非常量變量(第4.12.4節)。

參見爲技術背景的常量值inlining其他的答案。

3
String staticvar =StaticTest.STATIC_VAR; 

不加載類StaticTest。相反,編譯器內嵌的常數爲MainClass。因此,在運行時,該代碼將被執行:

String staticvar = "Static Var"; 

的JLS調用此一「constant」:

原始類型或String類型的變量,也就是最後的和與編譯初始化 時間常量表達式(§15.28),被稱爲常量變量 。

這意味着StaticTest.init();是VM第一次實際加載類。這會導致靜態塊的執行。

3

因爲變量是public static final它被編譯器內聯。

所有對它的引用都被替換爲實際值,因爲它不能改變,這就是所謂的編譯時間常量。

public static final String STATIC_VAR=getStaticVar(); 
private static String getStaticVar() { 
    return "Static Var"; 
} 

你會得到你所期望的結果 - 如果你的值賦給一個方法的返回值

System.out.println("Test static initialization"); 
String staticvar = "Static Var"; 

您的代碼基本上被編譯成。

有一個good SO answer解釋內聯和由JLS給出的編譯時間常量的保證。