简体   繁体   English

什么时候初始化静态变量?

[英]When are static variables initialized?

I am wondering when static variables are initialized to their default values.我想知道静态变量何时初始化为其默认值。 Is it correct that when a class is loaded, static vars are created (allocated), then static initializers and initializations in declarations are executed?加载类时,创建(分配)静态变量,然后执行静态初始化程序和声明中的初始化是否正确? At what point are the default values are given?在什么时候给出默认值? This leads to the problem of forward reference.这就导致了前向引用的问题。

Also please if you can explain this in reference to the question asked on Why static fields are not initialized in time?另外请您参考为什么静态字段没有及时初始化? and especially the answer given by Kevin Brock on the same site.尤其是 Kevin Brock 在同一站点上给出的答案。 I can't understand the 3rd point.看不懂第三点。

From See Java Static Variable Methods :参见 Java 静态变量方法

  • It is a variable which belongs to the class and not to object(instance)它是属于类而不属于对象(实例)的变量
  • Static variables are initialized only once , at the start of the execution.静态变量仅在执行开始时初始化一次。 These variables will be initialized first, before the initialization of any instance variables在初始化任何实例变量之前,将首先初始化这些变量
  • A single copy to be shared by all instances of the class由类的所有实例共享的单个副本
  • A static variable can be accessed directly by the class name and doesn't need any object.静态变量可以通过类名直接访问,不需要任何对象。

Instance and class (static) variables are automatically initialized to standard default values if you fail to purposely initialize them.实例和类(静态)变量如果您没有故意初始化它们,则会自动初始化为标准默认值。 Although local variables are not automatically initialized, you cannot compile a program that fails to either initialize a local variable or assign a value to that local variable before it is used.虽然局部变量不会自动初始化,但你不能编译一个在使用局部变量之前未能初始化局部变量或为该局部变量赋值的程序。

What the compiler actually does is to internally produce a single class initialization routine that combines all the static variable initializers and all of the static initializer blocks of code, in the order that they appear in the class declaration.编译器实际所做的是在内部生成一个类初始化例程,该例程按照它们在类声明中出现的顺序组合所有静态变量初始化器和所有静态初始化器代码块。 This single initialization procedure is run automatically, one time only, when the class is first loaded.这个单一的初始化过程在第一次加载类时自动运行,仅一次。

In case of inner classes, they can not have static fields对于内部类,它们不能有静态字段

An inner class is a nested class that is not explicitly or implicitly declared static .内部类是未显式或隐式声明为static的嵌套类。

... ...

Inner classes may not declare static initializers (§8.7) or member interfaces...内部类不能声明静态初始值设定项(第 8.7 节)或成员接口...

Inner classes may not declare static members, unless they are constant variables...内部类不能声明静态成员,除非它们是常量变量......

See JLS 8.1.3 Inner Classes and Enclosing Instances请参阅 JLS 8.1.3 内部类和封闭实例

final fields in Java can be initialized separately from their declaration place this is however can not be applicable to static final fields. Java 中的final字段可以与其声明位置分开初始化,但这不适用于static final字段。 See the example below.请参阅下面的示例。

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

This is because there is just one copy of the static variables associated with the type, rather than one associated with each instance of the type as with instance variables and if we try to initialize z of type static final within the constructor, it will attempt to reinitialize the static final type field z because the constructor is run on each instantiation of the class that must not occur to static final fields.这是因为与该类型关联的static变量只有一个副本,而不是像实例变量那样与该类型的每个实例关联一个副本,如果我们尝试在构造函数中初始化类型为static final z ,它将尝试重新初始化static final类型字段z因为构造函数在类的每个实例化上运行,静态final字段不得出现。

See:看:

The last in particular provides detailed initialization steps that spell out when static variables are initialized, and in what order (with the caveat that final class variables and interface fields that are compile-time constants are initialized first.)最后一个特别提供了详细的初始化步骤,阐明了何时初始化静态变量,以及初始化的顺序(需要注意的是,作为编译时常量的final类变量和接口字段首先被初始化。)

I'm not sure what your specific question about point 3 (assuming you mean the nested one?) is.我不确定您对第 3 点的具体问题(假设您的意思是嵌套的?)。 The detailed sequence states this would be a recursive initialization request so it will continue initialization.详细序列说明这将是一个递归初始化请求,因此它将继续初始化。

Static fields are initialized when the class is loaded by the class loader.静态字段在类加载器加载类时初始化。 Default values are assigned at this time.此时分配默认值。 This is done in the order than they appear in the source code.这是按照它们在源代码中出现的顺序完成的。

The order of initialization is:初始化的顺序是:

  1. Static initialization blocks静态初始化块
  2. Instance initialization blocks实例初始化块
  3. Constructors构造函数

The details of the process are explained in the JVM specification document.该过程的详细信息在 JVM 规范文档中进行了解释。

static variable静态变量

  • It is a variable which belongs to the class and not to object(instance)它是属于类而不属于对象(实例)的变量
  • Static variables are initialized only once , at the start of the execution(when the Classloader load the class for the first time) .静态变量仅在执行开始时初始化一次(当类加载器第一次加载类时)。
  • These variables will be initialized first, before the initialization of any instance variables在初始化任何实例变量之前,将首先初始化这些变量
  • A single copy to be shared by all instances of the class由类的所有实例共享的单个副本
  • A static variable can be accessed directly by the class name and doesn't need any object静态变量可以通过类名直接访问,不需要任何对象

The static variable can be intialize in the following three ways as follow choose any one you like静态变量可以通过以下三种方式初始化,如下选择你喜欢的任何一种

  1. you can intialize it at the time of declaration您可以在声明时初始化它
  2. or you can do by making static block eg:或者您可以通过制作静态块来完成,例如:

     static { // whatever code is needed for initialization goes here }
  3. There is an alternative to static blocks — you can write a private static method有一个静态块的替代方案——你可以写一个私有的静态方法

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

Starting with the code from the other question:从另一个问题的代码开始:

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

A reference to this class will start initialization.对此类的引用将开始初始化。 First, the class will be marked as initialized.首先,该类将被标记为已初始化。 Then the first static field will be initialized with a new instance of MyClass().然后第一个静态字段将使用 MyClass() 的新实例进行初始化。 Note that myClass is immediately given a reference to a blank MyClass instance.请注意, myClass 立即获得了对空白MyClass 实例的引用。 The space is there, but all values are null.空间在那里,但所有值都为空。 The constructor is now executed and prints obj , which is null.现在执行构造函数并打印obj ,它为 null。

Now back to initializing the class: obj is made a reference to a new real object, and we're done.现在回到初始化类: obj被引用到一个新的真实对象,我们就完成了。

If this was set off by a statement like: MyClass mc = new MyClass();如果这是由以下语句引起的: MyClass mc = new MyClass(); space for a new MyClass instance is again allocated (and the reference placed in mc ).再次为新的 MyClass 实例分配空间(并将引用放在mc )。 The constructor is again executed and again prints obj , which now is not null.构造函数再次执行并再次打印obj ,它现在不为空。

The real trick here is that when you use new , as in WhatEverItIs weii = new WhatEverItIs( p1, p2 );这里真正的技巧是当你使用new ,就像WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii is immediately given a reference to a bit of nulled memory. weii立即被赋予一个对空内存位的引用。 The JVM will then go on to initialize values and run the constructor.然后 JVM 将继续初始化值并运行构造函数。 But if you somehow reference weii before it does so--by referencing it from another thread or or by referencing from the class initialization, for instance--you are looking at a class instance filled with null values.但是,如果你它这样做之前以某种方式引用了weii通过从另一个线程引用它或通过从类初始化引用,例如——你正在查看一个填充了空值的类实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM