2013-12-16 106 views
4

中的行爲有所不同在學習Java認證測試時,我瞭解到靜態初始化塊在加載類時運行一次,按照源代碼中的外觀順序運行,該實例每次創建實例時都會運行初始化塊,並且每次在此之後創建實例時,構造函數中的代碼都會運行。爲了測試我創建了一個包含一些靜態和實例init塊的類以及一個包含打印內容的構造器。一切按預期工作 - 除了我認爲「加載」意味着在運行時,但我想這是在創建第一個實例時發生的,因爲除非創建至少一個類實例,否則我根本沒有得到任何輸出。然後我試着用enum來試試,命令全部關閉。首先,枚舉首次在代碼中被引用時,初始化塊爲枚舉所具有的每個值運行一次 - 其次,在我假設的實例init塊之後,標記爲靜態運行的init塊!這與我的預期相反。這是我的問題的細分。爲什麼Enums中的靜態和實例初始化塊的行爲與類

  1. 爲什麼標記爲靜態的init塊在枚舉中最後運行?
  2. 枚舉是否可以有實例init塊?
  3. 爲什麼我認爲塊實例初始化塊只運行一次枚舉加載時,而不是每次一個新的枚舉值被引用?
  4. 當類被「加載」時,類靜態初始化塊運行。加載意味着什麼?在類中實例化對象時會發生一次嗎?

謝謝!這對我來說非常混亂。

public class EnumInit { 
public static void main(String[] args) { 
    System.out.println(Color.RED.toString() + " Main"); 
    MyInit myInit = new MyInit(); 
    System.out.println(Color.BLUE.toString() + " Main"); 
    MyInit mySecondInit = new MyInit(); 

} 
} 

enum Color {  
RED, BLUE, GREEN; 
String instanceVar = "Enum Instance Variable Text"; 
static { System.out.println("Enum Static init block 1"); } 
{ System.out.println("Enum Instance init block 1"); } 
static { System.out.println("Enum Static static init block 2"); } 
Color() { 
    System.out.println(instanceVar); 
    System.out.println("Enum String Literal"); 
} 
{ System.out.println("Enum Instance init block 2"); } 
} 

class MyInit { 
String instanceVar = "Class Instance Variable Text"; 
static { System.out.println("Class Static init block 1"); } 
{ System.out.println("Class Instance init block 1"); } 
static { System.out.println("Class Static static init block 2"); } 
MyInit() { 
    System.out.println(instanceVar); 
    System.out.println("Class String Literal"); 
} 
{ System.out.println("Class Instance init block 2"); } 
} 
+0

#4:類沒有加載,直到他們有有意義的使用。這可能是調用類的靜態方法,或創建一個實例,或者調用Class.forName()或其他。我相信這是爲了將當前加載到perma gen的類的數量降到最低。 –

回答

7

Java Language Specification says this about enum constants

除此之外枚舉類型E從枚舉繼承成員, 每個聲明枚舉名稱爲常值N,枚舉類型有一個 隱含聲明爲public E類型的名爲n的靜態最終字段。這些 字段被視爲以與枚舉類型中聲明的任何靜態字段顯式地 相對應的枚舉常量的相同順序聲明爲 。每個這樣的字段被初始化爲與其對應的枚舉 常量。

所以

enum Color {  
    RED, BLUE, GREEN; 
    ... 
} 

實際上是

public static final Color RED = new Color(); 
public static final Color BLUE = new Color(); 
public static final Color GREEN = new Color(); 

,將您有static塊之前得到評估。

爲什麼標記爲靜態的init塊最後在枚舉中運行?

參見上文。

枚舉是否有實例init塊?

是的,編譯你的代碼,你會看到。

爲什麼我認爲塊實例初始化塊只運行一次枚舉加載時,而不是每次引用新的枚舉值?

一旦枚舉類型被初始化,就會創建(實例化)枚舉常量。你不創建一個新的enum任何時候,你做

Color color = Color.RED; 

你只是引用一個已經創建,現有對象。

當一個類被「加載」時,類靜態初始化塊運行。加載意味着什麼?在類中實例化對象時會發生一次嗎?

當一個類在JVM中第一次被引用時,它被ClassLoader加載並初始化。 Read more about it here.

+0

那麼當每個隱式構造函數運行時,沒有標記爲靜態運行的init塊,然後靜態塊最後運行? – paniclater

+1

@paniclater是的,那些實例初始化塊在隱式地調用'new Color();'時運行。由於'enum'常量是您在'enum'的主體中聲明的第一件事,因此這些常量將在'enum'中聲明的靜態塊之前發生。 –

+0

謝謝,這實際上使這個過程非常清晰。 – paniclater

相關問題