好的,所以说我有一个看起来像这样的课程:
public class SignupServlet extends HttpServlet {
private static final Logger SERVLET_LOGGER=COMPANYLog.open(SignupServlet.class);
private static final ExceptionMessageHandler handler = new ExceptionMessageHandler();
private static final SignupServletObservableAgent signupObservableAgent =
new SignupServletObservableAgent(null, SERVLET_LOGGER);
}
我可以指望类加载器按顺序初始化这些字段,这样我可以依赖SERVLET_LOGGER在signupObservableAgent之前实例化吗?
答案 0 :(得分:49)
是的,它们按照它们在源中出现的顺序进行初始化。您可以在The Java Language Specification, §12.4.2中阅读所有血腥细节。见步骤9,其中包括:
...以文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样,除了最终的类变量和接口的字段的值是编译时常量首先初始化...
答案 1 :(得分:3)
我认为可以重新排序静态字段的初始化。至少这是我理解JMM specification
的方式在许多情况下,对程序变量(对象实例字段,类静态字段和数组元素)的访问可能看起来以与程序指定的顺序不同的顺序执行。
答案 2 :(得分:1)
如果有子类和超类。
答案 3 :(得分:0)
不是真的回答问题,而是在这里询问更多-)。刚遇到一个有趣的例子,介绍了静态字段初始化顺序。这是示例:
public class Foo {
private static final Long result = method1();
private static String string = "something";
private static Long method1() {
if (string == null) {
throw new IllegalStateException("BOOM");
}
return 1L;
}
public static void main(String[] args) {
System.out.println("here");
}
}
这将产生IllegalStateException。我知道这里的顺序是,首先我们评估“结果”字段,该字段调用method1()并绕过“字符串”值初始化。 “字符串”是一个常量,但是我在编写测试时忘记放置“最终”修饰符。但是这种情况是否应该在运行时处理?含义当我们调用“ if(string == null)”时,JRE是否应该足够聪明才能验证“ string”是否尚未初始化并进行初始化?
答案 4 :(得分:-1)
这是一个可以使用静态块的地方,可以保证执行顺序。
public class SignupServlet extends HttpServlet {
private static final Logger SERVLET_LOGGER;
private static final ExceptionMessageHandler handler;
private static final SignupServletObservableAgent signupObservableAgent;
static {
SERVLET_LOGGER = COMPANYLog.open(SignupServlet.class);
handler = new ExceptionMessageHandler();
signupObservableAgent = new SignupServletObservableAgent(null, SERVLET_LOGGER);
}
}