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

Java 外部类中的静态初始化器是否保证在内部枚举初始化之前运行?,java,enums,initialization,static-initialization,Java,Enums,Initialization,Static Initialization,我正试图从配置文件加载一些日志消息,但我仍然希望通过enum引用它们的名称,而不是在将它们的名称键入为Strings时遇到打字错误。下面是我的设置: public class Log { private static final Logger LOGGER = Logger.getLogger(Log.class); private static final String MESSAGES_FILE_PATH = "conf/log_message.conf"; pr

我正试图从配置文件加载一些日志消息,但我仍然希望通过
enum
引用它们的名称,而不是在将它们的名称键入为
String
s时遇到打字错误。下面是我的设置:

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
s初始化之前不运行。我已经测试了代码,到目前为止,它工作得很好,从逻辑上讲,我看不出静态初始值设定项如何不能首先运行(因为对
Message
的引用必须经过
Log
,例如
Log.Message.IOEXCEPTION
)。尽管如此,我对设置还是有点不安,不想留下任何可能导致应用程序崩溃的漏洞。那么,这安全吗?

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

private Message() {
    text = MESSAGES.getProperty(name());
}   //        ^ static field of Log
访问
消息
将导致
日志
加载并初始化(如果尚未加载)

“我不明白静态初始值设定项如何不能首先运行(因为对消息的引用必须经过日志,例如Log.Message.IOEXCEPTION)”

通过外部类名访问嵌套类不会导致外部类被初始化

下面是导致类初始化()的原因列表:

  • T是一个类,并且创建了T的一个实例

  • T是一个类,调用由T声明的静态方法

  • 分配了一个由T声明的静态字段

  • 使用T声明的静态字段,该字段不是常量变量(§4.12.4)。

  • T是一个顶级类(§7.6),执行嵌套在T(§8.1.3)中的assert语句(§14.10)

(导致
Log
被初始化的代码被加了胆。)

尽管
消息
是静态的和最终的,但在JLS眼中它不是一个恒定的变量。中的常量变量定义如下:

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


JLS中详细介绍了启动和初始化过程。我在中看到的唯一一件事是:
如果C是一个类而不是一个接口,并且它的超类SC尚未初始化,那么递归地为SC执行整个过程。如果需要,首先验证并准备SC。
但是
消息
不是
日志
的扩展,它是一个内部类,我不认为有任何细节可以保证订单。也许我在浏览JLS时漏掉了一些东西。这不是一个常量变量吗
private static final
还是其他意思?编辑我的答案以解决您关于static final的问题,因为我的评论太长了。明白了。谢谢!真棒,全面的答案。