Java:初始化静态最终字段的顺序是什么?

时间:2010-12-15 02:02:19

标签: java static initialization classloader final

好的,所以说我有一个看起来像这样的课程:

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之前实例化吗?

5 个答案:

答案 0 :(得分:49)

是的,它们按照它们在源中出现的顺序进行初始化。您可以在The Java Language Specification, §12.4.2中阅读所有血腥细节。见步骤9,其中包括:

  

...以文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样,除了最终的类变量和接口的字段的值是编译时常量首先初始化...

答案 1 :(得分:3)

我认为可以重新排序静态字段的初始化。至少这是我理解JMM specification

的方式
  

在许多情况下,对程序变量(对象实例字段,类静态字段和数组元素)的访问可能看起来以与程序指定的顺序不同的顺序执行。

答案 2 :(得分:1)

如果有子类和超类。

  1. EX: ' A' :超级 ' B' :子类,它扩展了超类' A'
  2. 当B类加载时,A类也加载
  3. 所有静态变量都使用来自' A'的默认值获取内存。和' B'类
  4. 然后静态成员(静态变量,静态块)按照“A' A'的上下顺序执行。上课然后' B'他们宣布了阶级。 最后自动从子类执行的main方法。

答案 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);
   } 
}