什么时候静态variables被初始化?

我想知道什么时候静态variables被初始化为默认值。 是否正确的是,当一个类被加载,静态variables被创build(分配),然后执行声明中的静态初始化和初始化? 在什么时候给出默认值? 这导致了前瞻性的问题。

另外,如果你能解释这个问题,请参考问题为什么静态字段没有及时初始化? 特别是Kevin Brock在同一个网站上的回答。 我不明白第三点。

  • 它是属于类的variables而不是对象(实例)
  • 在执行开始时,静态variables只被初始化一次。
  • 在初始化任何实例variables之前,这些variables将被初始化
  • 一个副本由该类的所有实例共享
  • 静态variables可以直接通过类名访问,不需要任何对象。 请参阅Java静态variables方法 。

如果您未能特意初始化它们,则实例和类(静态)variables会自动初始化为标准默认值。 尽pipe本地variables不会自动初始化,但是您不能编译程序,无法初始化本地variables或在使用本地variables之前为其分配值。

编译器实际上做的是在内部产生一个类初始化例程,它按照它们出现在类声明中的顺序将所有的静态variables初始值设定项和所有的静态初始值设定项块组合在一起。 这个单一的初始化过程是自动运行的,只有一次,当第一次加载类。

内部类的情况下,他们不能有静态字段

一个内部类是一个嵌套类,不是明确或隐式地声明为静态的。 内部类可能不声明静态初始值设定项(§8.7)或成员接口。 内部类可能不声明静态成员,除非它们是编译时常量字段“

请参阅JLS 8.1.3内部类和Enclosing实例

Java中的final字段可以从它们的声明位置单独初始化,但这不能适用于static final字段。 看下面的例子。

 final class Demo { private final int x; private static final int z; //must be initialized here. static { z = 10; //It can be initialized here. } public Demo(int x) { this.x=x; //This is possible. //z=15; compiler-error - can not assign a value to a final variable z } } 

这是因为只有一个与该types相关的staticvariables副本 ,而不是与实例variables的每个types实例关联的副本,如果我们尝试在构造函数中初始化types为static final z ,它将尝试重新初始化static finaltypes字段z因为构造函数在类的每个实例化上运行,而静态final字段则不会出现该实例。

看到:

  • JLS 8.7,静态初始化器
  • JLS 12.2,类和接口的加载
  • JLS 12.4,类和接口的初始化

最后一个特别提供了详细的初始化步骤 ,明确何时初始化静态variables,以及按照什么顺序( final初始化final类variables和接口字段是编译时常量)。

我不确定你对第3点的具体问题(假设你的意思是嵌套的)是什么。 详细的序列状态这将是一个recursion的初始化请求,所以它将继续初始化。

初始化的顺序是:

  1. 静态初始化块
  2. 实例初始化块
  3. 构造函数

在JVM 规范文档中解释了这个过程的细节。

当类加载器加载类时,静态字段将被初始化。 默认值是在这个时候分配的。 这是按照它们出现在源代码中的顺序完成的。

静态variables

  • 它是属于类的variables而不是对象(实例)
  • 在执行开始时(静态variables初始化一次,Classloader第一次加载类)。
  • 在初始化任何实例variables之前,这些variables将被初始化
  • 一个副本由该类的所有实例共享
  • 静态variables可以直接通过类名访问,不需要任何对象

从另一个问题的代码开始:

 class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); // will print null once } } 

对这个类的引用将开始初始化。 首先,这个类将被标记为初始化。 然后,第一个静态字段将使用MyClass()的新实例进行初始化。 请注意,myClass会立即引用空白的 MyClass实例。 空间在那里,但所有的值都是空的。 现在执行构造函数并打印obj ,它是null。

现在回到初始化类: obj被引用到一个新的真实对象,我们完成了。

如果这是由一个像这样的声明: MyClass mc = new MyClass(); 一个新的MyClass实例的空间再次被分配(并且引用被放置在mc )。 构造函数再次执行,并再次打印obj现在不是null。

真正的诀窍是,当你使用new ,如WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii立即给出了一些weii内存的参考。 JVM将继续初始化值并运行构造函数。 但是,如果你在某种程度上引用了weii 例如通过从另一个线程引用它,或者通过从类初始化引用它,你正在查看一个填充了null值的类实例。

静态variables可以通过以下三种方式进行初始化,如下所示select你喜欢的任何一个

  1. 你可以在声明的时候初始化它
  2. 或者你可以做静态块例如:*

    静态{/ /任何代码是需要进行初始化去这里}

*

  1. 有一个替代静态块 – 你可以写一个私人的静态方法

 class name { public static varType myVar = initializeVar(); private static varType initializeVar() { // initialization code goes here } }