I am trying to piece together the process of Initialization and Instantiation in the JVM but the JLS is a little obtuse on a few details, so if anyone would mind clearing up some details it would be appreciated. This is what I have been able to figure out so far.
Initialization
Recursively Initialize static final variables of the class and it's interfaces that are compile time constants.
Back out of the recursion processing static blocks and static fields in textual order.
Instantiation
Recursively Initialize final instance variables of the class that are compile time constants.
Back out of the recursion processing non-static blocks and instance fields in textual order prepending them to the constructors as it returns.
Okay, so now for the questions.
are interfaces processed in order of declaration?
are interfaces processed in a separate recursive stack?
a) if yes, do interfaces get processed before or after superclasses?
b) if yes, am I correct in deducing that one or the others (Interface or Superclass) gets its non-compile-time constant fields initialized before the others compile-time constants.
What role does calls to the nondefault super() constructor play in this process?
Am I mistaken in any of my conclusions?
Am I missing any other key details?
Following is an example that print the order of each step during object creation.
InstanceCreateStepTest.java:
Execution:
Just invoke the main method, and then check the output.
Tips:
@PostConstruct
won't be invoked, unless you invoke it inside some container, likeSpring-boot
, since it depends on those containers to implement annotation like@PostConstruct
.It is important to distinguish between the initialization of a class, and initialization of an object.
Class Initialization
A class or interface is initialized upon first access, by assigning the compile time constant fields, then recursively initializing the superclass (if not already initialized), then processing the static initializers (which include the initializers for for the static fields that are not compile time constants).
As you have noticed, initialization of a class does not, by itself, trigger initialization of the interfaces it implements. Interfaces are therefore initialized when they are first accessed, typically by reading a field that is not a compile time constant. This access may occur during evaluation of an initializer, causing a recursive initialization.
It is also worth noting that initialization is not triggered by accessing fields that are compile time constants, as these are evaluated at compile time:
Object Initialization
An object is initialized whenever a new object is created, typically by evaluation of a class instance creation expression. This proceeds as follows:
As we can see in step 3, the presence of an explicit call to the super constructor simply changes which super class constructor is invoked.