首页 文章

何时初始化静态变量?

提问于
浏览
62

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

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

7 回答

  • 6

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

    • 您可以在申报时初始化它

    • 或者您可以通过制作静态块例如:*

    static {//初始化需要的代码在这里}

    • 有静态块的替代方法 - 您可以编写私有静态方法

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

  • 6

    看到:

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

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

  • 3

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

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

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

    对于 inner 类,它们不能具有静态字段

    内部类是未显式或隐式声明为静态的嵌套类 . ...内部类可能不会声明静态初始化器(第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
        }
    }
    

    这是因为只有一个_2803560_与该类型相关联的 static 变量,而不是与实例变量相关的每个类型实例,如果我们尝试在构造函数中初始化类型 static finalz ,它将尝试重新初始化 static final 类型字段 z 因为构造函数在类的每个实例化上运行,而静态 final 字段不得出现 .

  • 14

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

  • 55

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

    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 立即被赋予对一些空的内存的引用 . 然后,JVM将继续初始化值并运行构造函数 . 但是如果你在它之前以某种方式引用 weii - 通过从另一个线程引用它或者从类初始化引用它 - 例如 - 你正在查看填充的类实例具有空值 .

  • 2

    静态变量

    • 它是属于类的变量而不是对象(实例)

    • 静态变量仅在执行开始时初始化一次(当Classloader第一次加载类时) .

    • 在初始化任何实例变量之前,将首先初始化这些变量

    • 要由该类的所有实例共享的单个副本

    • 静态变量可以由类名直接访问,不需要任何对象

  • 3

    初始化顺序是:

    • 静态初始化块

    • 实例初始化块

    • 构造函数

    JVM specification文档中说明了该过程的详细信息 .

相关问题