2014-02-09 82 views
2

我試圖從配置文件中加載一些日誌消息,但我仍然希望通過enum來引用它們的名稱,而不是像String那樣輸入名稱時打開自己的typographcial錯誤。因此,這裏是我的設置:外部類中的靜態初始化器是否保證在內部枚舉初始化之前運行?

public class Log { 

    private static final Logger LOGGER = Logger.getLogger(Log.class); 
    private static final String MESSAGES_FILE_PATH = "conf/log_message.conf"; 

    private static final Properties MESSAGES = new Properties(); 
    static { 
     try { 
      MESSAGES.load(new FileInputStream(new File(MESSAGES_FILE_PATH))); 
     } 
     catch(IOException ioe) { 
      LOGGER.fatal("Unable to load log messages from file: " + MESSAGES_FILE_PATH, ioe); 
     } 
    } 

    public enum Message { 

     //Main 
     PROGRAM_EXIT, 
     THREAD_INTERRUPTED, 
     FATAL_TERMINATING_ERROR, 
     SHUTDOWN_HOOK_EXCEPTION, 
     IO_READ_ATTEMPT, 
     IO_READ_FAILURE, 
     IO_WRITE_ATTEMPT, 
     IO_WRITE_FAILURE, 
     IOEXCEPTION, 

     //... 

     private final String text; 

     private Message() { 
      text = MESSAGES.getProperty(name()); 
     } 

     //... 
    } 
} 

我擔心的是,可能會有一些邊緣情形,其中enum s的初始化之前在Log靜態初始化不運行。我已經測試了代碼,到目前爲止它工作正常,並且從邏輯上看,我沒有看到靜態初始化程序如何能夠首先運行而不是(因爲引用Message必須經過Log,例如Log.Message.IOEXCEPTION)。不過,我對安裝有點不安,並且不想爲應用程序崩潰留下任何可能的漏洞。那麼,這是安全的嗎?

+1

啓動和初始化過程詳見JLS。 –

+0

我在[JLS詳圖初始化](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.5)中看到的唯一一件事就是:'如果C是一個類而不是接口,它的超類SC尚未初始化,然後遞歸執行SC的整個過程。如果有必要的話,先驗證並準備好SC。但是'Message'不是'Log'的擴展,它是一個內部類,我沒有看到任何細節將其作爲保證順序。不過,也許我在瀏覽JLS時錯過了一些東西。 – asteri

回答

2

你擔心的是,枚舉會以某種方式訪問​​,而沒有外部類的靜態初始化,但這是不可能的。枚舉訪問外部類成員:

private Message() { 
    text = MESSAGES.getProperty(name()); 
} //  ^static field of Log 

訪問MESSAGES會導致Log被加載和初始化,如果它是不是已經。

「我看不出靜態初始化可能永遠不會首先運行(因爲對消息的引用要經過登錄,如Log.Message.IOEXCEPTION)」

訪問嵌套類通過外部類名不會導致外部類被初始化。

爲了記錄在案,這裏是什麼原因導致列表中的類初始化(JLS 12.4.1):

  • T是一個類,並創建T的實例。

  • T是一個類,由T聲明的靜態方法被調用。

  • 指定由T聲明的靜態字段。

  • 使用由T聲明的靜態字段,該字段不是常量變量(§4.12.4)。

  • T是一個頂級類(第7.6節),並且執行了一個在T(§8.1.3)中在詞彙上嵌套的斷言語句(第14.10節)。

(底氣是一個引起Log被初始化。)

雖然MESSAGES是靜態的,最終,它不是在JLS的眼睛中的常量變量。常量變量在final Variables中定義如下:

原始類型或類型String的變量,它是最終的並用編譯時常量表達式初始化...

+0

是不是一個常量變量? '私人靜態最終'還是別的意思? – asteri

+0

編輯我的答案,以解決您關於靜態最終的問題,因爲我的評論太長了。 – Radiodef

+0

明白了。非常感謝!真棒,全面的答案。 – asteri