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

38

好的,假设我有一个类看起来像这样:

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个回答

58

是的,它们按照在源代码中出现的顺序进行初始化。您可以在Java语言规范第12.4.2节中阅读所有详细信息。请看第9步,它说:

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


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

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


3
这部分还表明:“...并且变量b的值 取决于变量a的值,那么编译器可以自由地重新排列这些操作,...” - Olaf Dietsche
1
该引用是关于访问而不是初始化的。 - user207421

1

如果有子类和父类。

  1. 例如: 'A':父类 'B':子类,它扩展了父类 'A'
  2. 当加载B类时,也会加载A类
  3. 所有静态变量都会从'A'和'B'类中获得默认值的内存
  4. 然后按照'A'类和'B'类中声明的顺序依次执行静态成员(静态变量,静态块)。 最后自动从子类执行主方法。

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。我理解这里的顺序是首先评估“result”字段,该字段调用method1()并绕过“string”值初始化。“string”应该是一个常量,但当编写测试时,我忘记了放置“final”修饰符。但是,这种情况是否应在运行时处理?也就是说,当我们调用“if(string == null)”时,JRE是否足够聪明,能够去验证“string”尚未初始化并对其进行初始化?


-2

这是一个您可以使用静态块的地方,它将保证执行顺序。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接