I tried to understand the behavior of initialization order when static fields are initialized with a reference to the same enclosing class object.
public class Test {
static final Test t=new Test();
static int a=5;
Test(){
System.out.println("a="+a);
}
public static void main(String[] args) {
new Test();
}
}
Output of above piece of code is:
a=0
a=5
If I modify variable a
to anything else other than plain static
:
static final a=5;
a=5;
final a=5;
The output is:
a=5
a=5
Why is this behavior?
Note that the output is a=5 & a=5
even when both t & a
are declared as static final
in which case t
precedes the declaration of a
static final members are initialized before other static members.
non final static members are initialized in order of appearance
Therefore, in your first case :
static Test t=new Test();
static int a=5;
The constructor is first called before a
is initialized, so a=0
is displayed.
In the second case, static final a
is initialized before t
, so a=5
is displayed when the first instance of Test
is created. When a
is not static, it is initialized prior to the execution of the constructor, so again a=5
is displayed.
Regarding the edit in your question.
Looking at section 12.4.2 of the JLS :
- Then, initialize the final class variables and fields of interfaces whose values are compile-time constant expressions (§8.3.2.1, §9.3.1, §13.4.9, §15.28).
...
- Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
You see that final class variables (i.e. static final) are initialized before the rest of the static variables only if their values are compile time constant expressions. 5
is a constant expression. new Test()
is not. Therefore a
is initialized before t
even if both are static final.