2

我正在尝试从配置文件中加载一些日志消息,但我仍然想通过 an 引用他们的名字,而不是在将他们的名字输入为senum时打开自己的印刷错误。String所以这是我的设置:

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

        //...
    }
}

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

4

1 回答 1

2

您担心的是枚举会在没有其外部类的静态初始化的情况下以某种方式访问​​,但这是不可能的。枚举访问外部类成员:

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 节)。

(加粗是导致Log被初始化的原因。)

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

原始类型或字符串类型的变量,它是最终的并使用编译时常量表达式初始化...

于 2014-02-09T19:26:57.017 回答