Why static fields are not initialized in time?
The following code prints null
once.
class MyClass {
private static MyClass myClass = new MyClass();
private static final Object obj = new Object();
public MyClass() {
System.out.println(obj);
}
public static void main(String[] args) {}
}
Why are the static objects not initialized before the constructor runs?
Update
I'd just copied this example program without attention, I thought we were talking about 2 Object开发者_开发知识库 fields, now I saw that the first is a MyClass field.. :/
Because statics are initialized in the order they are given in source code.
Check this out:
class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}
That will print:
null
null
myClassObject
null
EDIT
Ok let's draw this out to be a bit more clear.
- Statics are initialized one by one in the order as declared in the source code.
- Since the first static is initialized before the rest, during its initialization the rest of the static fields are null or default values.
- During the initiation of the second static the first static is correct but the rest are still null or default.
Is that clear?
EDIT 2
As Varman pointed out the reference to itself will be null while it is being initialized. Which makes sense if you think about it.
Let's try a different way to explain this...
This is the sequence the JVM goes through when you first reference the class MyClass
.
- Load the byte-code into memory.
- Memory for the static storage is cleared (binary zero).
- Initialize the class:
- Execute each static initializer in the order that it appears, this includes static variables and
static { ... }
blocks. - JVM then initializes your
myClass
static variable to a new instance ofMyClass
. - When this happens, the JVM notices that
MyClass
is already loaded (byte-code) and in the process of being initialized, so it skips initialization. - Allocate memory on heap for object.
- Execute constructor.
- Print out value of
obj
which is stillnull
(since it is not part of the heap and constructor initialized variables). - When constructor finishes, execute next static initializer which sets
obj
to a new instance ofObject
.
- Execute each static initializer in the order that it appears, this includes static variables and
- Class initialization done. From this point, all constructor calls will behave as you presume/expect - that is
obj
would not benull
but a reference to anObject
instance.
Remember that Java specifies that a final
variable is assigned a value once. It is not that it is guaranteed to be assigned a value when the code references it unless you ensure that the code references it after it is assigned.
This is not a bug. This is the defined way to handle usage of the class during its own initialization. If this were not so, then the JVM would go into an infinite loop. See step #3.3 (if the JVM does not skip initialization for a class that is in the process of initialization it would just keep initializing it - infinite loop).
Note as well, this all happens on the same thread that first references the class. Second, the JVM guarantees that initialization will complete before any other thread is allowed to use this class.
That's because Java executes the static section in order it is declared. In your case, the sequence is
- new MyClass
- new Object
When #1 is executed, obj is still not initialized, so it prints null. Try the following and you will see the difference:
class MyClass {
private static final Object obj = new Object();
private static MyClass myClass = new MyClass();
public MyClass() {
System.out.println(obj); // will print null once
}
}
Generally speaking, it is better to avoid such a construct all together. If you are trying to create a singleton, that's how that code fragment should look like:
class MyClass {
private static final MyClass myClass = new MyClass();
private Object obj = new Object();
private MyClass() {
System.out.println(obj); // will print null once
}
}
that is because static fields initialized in same order they defined.
@Pyrolistical
since the initial of first static field myclass is not fully constructed ...the result i get is
null null testInitialize.MyObject@70f9f9d8 null
精彩评论