我正在尝试从配置文件中加载一些日志消息,但是我仍然希望通过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
)。不过,我对设置有点不安,并且不想为应用程序崩溃留下任何可能的漏洞。那么,这样安全吗?
答案 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的变量,是最终的并使用编译时常量表达式初始化...