Your Test compiles to:
public class Test { public static final Test me; public static final Integer I; public static final String S = "abc"; static { me = new Test(); I = Integer.valueOf(4); } public Test() { System.out.println(I); System.out.println("abc"); } public static Test getInstance() { return me; } public static void main(String[] args) { Test.getInstance(); } }
As you can see, the constructor for Test is called before I initialized. That is why it prints "null" for I If you had to change the declaration order for me and I , you will get the expected result, because I will be initialized before the constructor is called. You can also change the type for I from Integer to int .
Since 4 needs to get an autobox (i.e. wrapped in an Integer object), it is not a compile-time constant and is part of the static initializer block. However, if the type was int , the number 4 would be a compile-time constant, so it would not have to be explicitly initialized. Since "abc" is a compile-time constant, the value of S is output as expected.
If you replace,
public static final String S = "abc";
from,
public static final String S = new String("abc");
Then you will notice that the output of S is "null" . Why is this happening? For the same reason why I also prints "null" . Fields like these, which have literal, constant values ββ(autoboxing, for example String , are not required), the "ConstantValue" attribute when compiling, which means that their value can be resolved simply by searching in a constant pool of classes, without having to run any either code.
Martin Tuskevicius Sep 12 '16 at 15:41 2016-09-12 15:41
source share