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

Java:静态最终字段的初始化顺序是什么?,java,static,initialization,classloader,final,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(); priv

好的,假设我有一个这样的类:

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\u LOGGER在注册ObservableAgent之前进行实例化?

是的,它们是按它们在源代码中出现的顺序初始化的。你可以在中阅读所有血淋淋的细节。参见步骤9,内容如下:

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


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

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


如果存在子类和超类

  • 例: “A”:超级类 “B”:子类,它扩展了超类“A”
  • 当B类加载时,A类也加载
  • 所有静态变量都从'A'和'B'类中获取具有默认值的内存
  • 然后,静态成员(静态变量、静态块)按照“A”类的自上而下顺序执行,然后按照声明的顺序执行“B”类。 最后,主方法从子类自动执行

  • 这是一个可以使用静态块来保证执行顺序的地方

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

    不是真的回答这个问题,而是在这里问更多-。刚刚遇到一个有趣的静态字段初始化顺序示例。以下是一个例子:

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

    这将产生非法状态例外。我知道这里的顺序是首先计算“result”字段,它调用method1()并绕过“string”值初始化。“string”是一个常量,但我在编写测试时忘了放一个“final”修饰符。但是这种情况是否应该在运行时处理?这意味着当我们调用“if(string==null)”时,JRE是否应该足够聪明去验证“string”是否还没有初始化并初始化它

    这一部分还指出“…b的值不依赖于a的值,那么编译器可以自由地对这些操作重新排序,…”引用的是访问,而不是初始化。