静态类初始化何时发生?


110

静态字段何时初始化?如果我从不实例化一个类,而是访问一个静态字段,那么用于实例化私有静态字段的所有静态块和私有静态方法是否在那个瞬间被调用(按顺序)?

如果我调用静态方法怎么办?它也运行所有静态块吗?之前的方法?


Answers:


156

类的静态初始化通常在以下事件之一首次发生之前立即发生:

  • 创建该类的实例,
  • 该类的静态方法被调用,
  • 分配了该类的静态字段,
  • 使用了非常量的静态字段,或者
  • 对于顶级类,将执行词法嵌套在该类中的assert语句1

参见JLS 12.4.1

也可以通过使用Class.forName(fqn, true, classLoader)或缩写来强制类进行初始化(如果尚未初始化)Class.forName(fqn)


1-JLS for Java 6至Java 8中存在最后的要点,但显然在规范中是错误的。最终在Java 9 JLS中对其进行了纠正:请参见source


9
虽然有一个常见的陷阱。原始图元和Strings被替换且未引用。如果class Other { public static final int VAL = 10; }从某个类引用a MyClass { private int = Other.VAL; }Other则不会加载该类。相反,编译器将在编译时仅替换final字段。
拉斐尔·温特豪德

6
@RafaelWinterhalter-是的……这是恒定静态场的情况。
Stephen C

2
@RafaelWinterhalter,对于所有“静态最终”原语或String变量(仅由常量表达式初始化的变量)不是正确的。
卢·布洛赫

1
是的,在static通常的情况下,甚至不需要该字段。
拉斐尔·温特豪德

1
它是相同的编程语言。是。
Stephen C

14

静态字段在初始化期间初始化类加载(加载,链接和初始化) “阶段”阶段包括静态初始化程序及其静态字段的初始化。静态初始化器按照类中定义的文本顺序执行。

考虑示例:

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

之所以打印Test.b nullsayHello是因为在静态范围内调用时,静态变量a未初始化。


6
严格来说,初始化不是类加载的“阶段”。确实,如果应用程序实际上没有使用某些类,则可能会加载这些类,但不会对其进行初始化。
斯蒂芬·C

@Stephen C您说得对,我用它来缺少一个更好的术语,也许我会引用它。
naikus 2010年

@StephenC的意思是,在进行Class加载时,它将内存分配给静态变量(&方法),但是这些静态变量没有使用代码中提供的值初始化吗?因为这里似乎是当b-> sayHello()-> a时,“ a”在内存中,但尚未为其赋值。
Shabbir Essaji

基本上是。
斯蒂芬·C

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.