The initialization sequence is specified in JLS 12.5:
- First, memory is allocated for the new object
- Then all instance variables in the object (including the ones defined in this class and all of its superclasses) are initialized to their default values
- Finally, the constructor is called.
The relevant part of the spec is:
...
If there is not sufficient space available to allocate memory for the object, then creation of the class instance completes abruptly with an OutOfMemoryError. Otherwise, all the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.12.5).
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
...
This is one of the reasons that you should never invoke a non-final
method from a constructor: that method might be overridden by a subclass, in which case the method will be invoked before the subclass has the chance to set state that the method may need. Consider this example:
public class Super {
private final int superValue;
protected Super() {
superValue = getSuperValue();
}
protected int getSuperValue() {
return 1;
}
@Override
public String toString() {
return Integer.toString(superValue);
}
}
public class Sub extends Super {
private final int superValueOverride;
public Sub(int value) {
this.superValueOverride = value;
}
@Override
protected int getSuperValue() {
return superValueOverride;
}
public static void main(String[] args) {
Super s = new Sub(2);
System.out.println(s);
}
}
It looks like s.superValue
should be 2, right? After all, Sub
overrides getSuperValue()
to return the value of superValueOverride
, which is initialized to 2. But that method gets invoked before any of Sub
's fields are initialized (other than to their default values), so s.superValue
is actually 0 (the default value of superValueOverride
).
This is even weirder because superValueOverride
is final
, and yet it seems to change its value! It's 0 when Super
calls getSuperValue()
, and only after the Super
constructor finishes is it assigned its final value of 2 (or whatever is passed in to the constructor).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…