外部类中的静态初始化程序是否保证在内部枚举初始化之前运行?

时间:2014-02-09 19:03:59

标签: java enums initialization static-initialization

我正在尝试从配置文件中加载一些日志消息,但是我仍然希望通过enum引用他们的名字,而不是在输入String时打开自己的名字错误{1}}秒。所以这是我的设置:

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());
        }

        //...
    }
}

我担心的是,Log中的静态初始化程序可能会在enum初始化之前未运行。我已经测试了代码,到目前为止它工作正常,而且从逻辑上讲,我看不出静态初始化程序如何首先运行(因为对Message的引用必须去通过Log,例如Log.Message.IOEXCEPTION)。不过,我对设置有点不安,并且不想为应用程序崩溃留下任何可能的漏洞。那么,这样安全吗?

1 个答案:

答案 0 :(得分:2)

你担心的是,如果没有外部类的静态init,就可以以某种方式访问​​枚举,但这是不可能的。枚举访问外部类成员:

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

访问MESSAGES会导致Log加载并初始化(如果尚未加载)。

  

“我没看到静态初始化程序如何不能先运行(因为对Message的引用必须通过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节)。

  •   

(Emboldened是导致Log初始化的那个。)

虽然MESSAGES是静态的和最终的,但它在JLS眼中并不是一个常数变量。常量变量在final Variables中定义如下:

  

基本类型或类型String的变量,是最终的并使用编译时常量表达式初始化...

相关问题