此外,请解释一下有关在Why static fields are not initialized in time?上提出的问题的参考,并特别解释该网站上Kevin Brock所给出的第三点答案。
来自查看Java静态变量方法:
- 它是属于类而不是对象(实例)的变量
- 静态变量仅初始化一次,在执行开始时。这些变量将在任何实例变量初始化之前首先初始化
- 单个副本可以由类的所有实例共享
- 可以直接通过类名称访问静态变量,而不需要任何对象。
如果您未能刻意初始化实例和类(静态)变量,则会自动将其初始化为标准默认值。虽然局部变量不会自动初始化,但您不能编译未初始化局部变量或在使用前为该局部变量分配值的程序。
编译器实际上所做的是内部产生一个单个类初始化程序,该程序将所有静态变量初始化器和所有静态初始化器代码块按照它们出现在类声明中的顺序组合起来。此单个初始化过程在加载类时自动运行一次。
对于内部类,它们不能具有静态字段
内部类是未显式或隐式声明为
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
变量只有一个副本,而不是每个实例都有一个。如果我们试图在构造函数中初始化类型为static final
的z
,它将尝试重新初始化z
这个静态final
类型字段,因为构造函数在类的每次实例化时运行,这对于static final
字段不应发生。
当类被类加载器加载时,静态字段会被初始化。此时会分配默认值。这是按照它们在源代码中出现的顺序完成的。
参见:
尤其是最后一点提供了详细的初始化步骤,阐述了静态变量何时初始化以及按照什么顺序初始化(但需要注意的是,首先初始化的是final
类变量和编译期常量接口字段)。
我不确定您对第三个问题(假设您指的是嵌套的问题?)的具体问题是什么。详细的顺序说明这将是一个递归初始化请求,因此它将继续初始化。
从另一个问题的代码开始:
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实例的引用。该空间存在,但所有值都为null。现在执行构造函数并打印obj,它是null。
现在回到类的初始化:obj被赋予对新实际对象的引用,我们完成了。
如果这是由像MyClass mc = new MyClass();
这样的语句触发的,则再次分配新的MyClass实例的空间(并将引用放置在mc中)。构造函数再次执行并再次打印obj,此时obj不再为null。
真正的诀窍在于,当您使用new
时,例如WhateverItIs weii = new WhateverItIs(p1, p2);
,weii立即被赋予对nulled内存块的引用。JVM将继续初始化值并运行构造函数。但是,如果您以某种方式在其之前引用了weii-例如从另一个线程引用它或通过从类初始化引用-则您将看到一个填充有null值的类实例。
or you can do by making static block eg:
static {
// whatever code is needed for initialization goes here
}
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
}
}