何时初始化静态变量?

时间:2012-01-02 19:10:04

标签: java static initialization

我想知道什么时候将静态变量初始化为默认值。 加载类时是否正确创建(分配)静态变量, 然后执行声明中的静态初始化器和初始化? 在什么时候给出默认值?这导致了前向参考的问题。

另外,如果您可以参考Why static fields are not initialized in time?提出的问题,特别是Kevin Brock在同一网站上给出的答案,请解释一下。我无法理解第三点。

7 个答案:

答案 0 :(得分:58)

来自See Java Static Variable Methods

  
      
  • 它是属于类的变量而不是对象(实例)
  •   
  • 静态变量仅在执行开始时初始化一次。在初始化任何实例变量
  • 之前,将首先初始化这些变量   
  • 要由班级的所有实例共享的单个副本
  •   
  • 静态变量可以通过类名直接访问,不需要任何对象。
  •   

如果您没有故意初始化它们,实例和类(静态)变量会自动初始化为标准默认值。虽然局部变量不会自动初始化,但您无法编译无法初始化局部变量或在使用该局部变量之前为该局部变量赋值的程序。

编译器实际上做的是在内部生成单个类初始化例程,该例程将所有静态变量初始化器和所有静态初始化器代码块按它们在类声明中出现的顺序组合在一起。单个初始化过程仅在首次加载类时自动运行一次。

如果是内部类,则它们不能包含静态字段

  

内部类是一个非显式或隐式的嵌套类   声明static

     

...

     

内部类可能不会声明静态初始化器(第8.7节)或成员接口......

     

内部类可能不会声明静态成员,除非它们是常量变量......

请参阅JLS 8.1.3 Inner Classes and Enclosing Instances

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

这是因为与该类型相关联的static变量只有一个副本,而不是与实例变量相关的每个类型实例关联的变量,如果我们尝试在构造函数中初始化类型z的{​​{1}},它将尝试重新初始化static final类型字段static final,因为构造函数在类的每个实例化上运行,不能发生静态z字段。

答案 1 :(得分:14)

请参阅:

最后一个特别提供了detailed initialization steps,它在静态变量初始化时拼写出来,并以什么顺序进行拼写(需要注意的是final类变量和作为编译时常量的接口字段首先被初始化。)

我不确定您对第3点的具体问题(假设您的意思是嵌套的?)是。详细的序列说明这将是一个递归初始化请求,因此它将继续初始化。

答案 2 :(得分:7)

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

答案 3 :(得分:6)

初始化的顺序是:

  1. 静态初始化块
  2. 实例初始化块
  3. 构造
  4. JVM specification文档中解释了该过程的详细信息。

答案 4 :(得分:3)

静态变量

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

答案 5 :(得分:3)

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

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会立即获得对 blank MyClass实例的引用。空间在那里,但所有值都为空。现在执行构造函数并打印obj,它为空。

现在回到初始化类:obj成为对新实体的引用,我们已经完成了。

如果这是由以下语句引发的:MyClass mc = new MyClass();空间再次分配新的MyClass实例(并且引用放在mc中)。再次执行构造函数并再次打印obj now 不为空。

这里的真正诀窍是当你使用new时,就像在WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii中一样,会立即给出一些有效的内存。然后,JVM将继续初始化值并运行构造函数。但是,如果你以某种方式在之前引用weii 它之前 - 通过从另一个线程引用它或者从类初始化引用它 - 例如 - 你正在查看填充的类实例具有空值。

答案 6 :(得分:3)

静态变量可以通过以下三种方式初始化,如下所示选择任何一种

  1. 您可以在声明时将其初始化
  2. 或者您可以通过制作静态阻止来实现,例如:

    static {
            // whatever code is needed for initialization goes here
        }
    
  3. 还有静态块的替代方法 - 您可以编写私有静态方法

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