静态类初始化啥时候发生?

Posted

技术标签:

【中文标题】静态类初始化啥时候发生?【英文标题】:When does static class initialization happen?静态类初始化什么时候发生? 【发布时间】:2011-03-30 18:39:59 【问题描述】:

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

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

【问题讨论】:

与静态初始化块类似:***.com/questions/2007666/… 【参考方案1】:

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

创建了一个类的实例, 调用了类的静态方法, 分配了类的静态字段, 使用了非常量的静态字段,或者 对于***类,执行词法嵌套在类中的断言语句1

见JLS 12.4.1。

也可以通过使用Class.forName(fqn, true, classLoader) 或简写形式Class.forName(fqn) 来强制初始化一个类(如果它尚未初始化)


静态类初始化什么时候发生?

见上文。

静态字段什么时候初始化?

作为静态类初始化的一部分;见上文。

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

是的。 (模没有什么是真正瞬时的。)

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

是的,是的。


请注意,可以在其中构造代码以观察静态字段的默认初始化值。


1 - 最后一个要点出现在 Java 6 到 Java 8 的 JLS 中,但这显然是规范中的一个错误。它最终在 Java 9 JLS 中得到纠正:参见 source。

【讨论】:

虽然有一个常见的陷阱。原语和Strings 被替换而不被引用。如果您从某个类MyClass private int = Other.VAL; 引用class Other public static final int VAL = 10; ,则不会加载类Other。相反,编译器将在编译时简单地替换 final 字段。 @RafaelWinterhalter - 是的......这是 constant 静态字段的情况。 @RafaelWinterhalter,这不适用于所有“静态最终”原语或 String 变量,只有由常量表达式初始化的变量。 是的,而且这个字段甚至不需要是static,虽然这是常见的情况。 是同一种编程语言。是的。【参考方案2】:

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

考虑这个例子:

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 打印 null 是因为在静态范围内调用 sayHello 时,静态变量 a 未初始化。

【讨论】:

严格来说,初始化并不是类加载的“阶段”。实际上,如果应用程序实际上没有使用某些类,可能会被加载但永远不会被初始化。 @Stephen C 你说得对,我用它是因为没有更好的术语,也许我会引用它。 @StephenC 这是否意味着在类加载发生时,它将内存分配给静态变量(和方法),但这些静态变量没有使用代码中提供的值进行初始化?因为这里似乎当 b->sayHello()->a, 'a' 在内存中但尚未分配值。 基本上是的。 @StephenC,你能提供一些细节吗?正如我在链接阶段所知,它为静态变量分配内存并为其分配默认值。然后在初始化阶段,它为它们分配原始值。在本例中,b 为空,因为在初始化阶段,静态块是从父级到子级,从上到下执行的。【参考方案3】:

是的,所有静态初始化程序都在您第一次访问类之前运行。如果是其他方式,我会称之为错误。

【讨论】:

有一些方法可以在不初始化的情况下引用一个类。

以上是关于静态类初始化啥时候发生?的主要内容,如果未能解决你的问题,请参考以下文章

什么时候会发生类初始化

java类中的静态常量是啥时候初始化的

java中静态方法,静态变量,静态初始化器,构造函数,属性初始化都是啥时候调用的? 它们的先后顺序。

Java的静态块和初始化块分别何时执行?有啥区别?

类在什么时候加载和初始化

java中成员或类变量自动初始化是啥意思