Object Initialization Order in Java

An object is a chunk of memory bundled with the code that manipulates memory. In the memory, the object maintains its state (the values of its instance variables), which can change and evolve throughout its lifetime. To get a newly-created object off to a good start, its newly-allocated memory must be initialized to a proper initial state.Here we take an in-depth look at the mechanisms Java uses to manage object initialization.

Java's Initialization Mechanisms

At the beginning of an object's life, the Java virtual machine (JVM) allocates enough memory on the heap to accommodate the object's instance variables. When that memory is first allocated, however, the data it contains is unpredictable. If the memory were used as is, the behavior of the object would also be unpredictable. To guard against such a scenario, Java makes certain that memory is initialized, at least to predictable default values, before it is used by any code.

The Java language has three mechanisms dedicated to ensuring proper initialization of objects: instance initializers (also called instance initialization blocks), instance variable initializers, and constructors. (Instance initializers and instance variable initializers collectively are called "initializers.") All three mechanisms result in Java code that is executed automatically when an object is created. When you allocate memory for a new object with the new operator or the newInstance() method of class Class, the Java virtual machine will insure that initialization code is run before you can use the newly-allocated memory. If you design your classes such that initializers and constructors always produce a valid state for newly-created objects, there will be no way for anyone to create and use an object that isn't properly initialized.

Default initial values

If you provide no explicit initialization to instance variables, they will be awarded predictable default initial values, which are based only on the type of the variable. Table 1 shows the default initial values for each of the variable types. (These are the default initial values for both instance and class variables. Local variables are not given default initial values. They must be initialized explicitly before they are used.)

Type Default Value
boolean  false
byte  0
char \u0000
short 0
int 0
long 0L
float 0.0f
double 0.0d
Object Reference null

If you don't explicitly initialize an instance variable, that variable will retain its default initial value when new returns its object reference.

Constructor Initialization

In the source file, a constructor looks like a method declaration in which the method has the same name as the class but has no return type. For example, here is a constructor declaration for class Bowl:

public class Bowl {
    public Bowl() {
        System.out.println(var + "\t" + obj);

        var = 256;
        obj = new Object();
        System.out.println(var + "\t" + obj);
    }

    private int var;
    private Object obj;
}

public class BowlTest {
    public static void main(String[] args) {
        Bowl bowl = new Bowl();
    }
}

Here's the output:

0 null
256 java.lang.Object@dc6ecd

Static Data Initialization

When the data is static, the same thing happens; if it’s a primitive and you don’t initialize it, it gets the standard primitive initial values. If it’s a reference to an object, it’s null unless you create a new object and attach your reference to it.

If you want to place initialization at the point of definition, it looks the same as for non-statics. There’s only a single piece of storage for a static, regardless of how many objects are created. But the question arises of when the static storage gets initialized. An example makes this question clear:

public class Bowl {
    public Bowl() {
        System.out.println("The contructor of Bowl is invoked");
    }
}

public class CupBoard {
    public class CupBoard() {
        System.out.println(bowl);
        System.out.println("The contructor of CupBoard is invoked")
    }

    private static Bowl bowl = new Bowl();
}

public class CupBoardTest {
    public static void main(String[] args) {
        CupBoard cupBoard = new CupBoard();
        cupBoard = new CupBoard();
    }
}

Here's the output:

The contructor of Bowl is invoked
The contructor of CupBoard is invoked
The contructor of CupBoard is invoked

Non-static instance initialization

Java provides a similar syntax for initializing non-static variables for each object. Here’s an example:

public class Bowl {
    public Bowl() {
        System.out.println("The contructor of Bowl is invoked");
    }
}

public class Pan {
    public Pan() {
        System.out.println("The contructor of Pan is invoked");
    }
}

public class CupBoard {
    public class CupBoard() {
        System.out.println(bowl);
        System.out.println("The contructor of CupBoard is invoked")
    }

    private Pan pan = new Pan();
    private static Bowl bowl = new Bowl();
}

public class CupBoardTest {
    public static void main(String[] args) {
        CupBoard cupBoard = new CupBoard();
    }
}

Here's the output:

The contructor of Bowl is invoked
The contructor of Pan is invoked
The contructor of CupBoard is invoked

Static Initialization Blocks

A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code. And dont forget, this code will be executed when JVM loads the class. Let's see an example.

public class Bowl {
    public Bowl(int index) {
       System.out.println("The constructor of Bowl invoked #" + index);
    }
}

public class CupBoard {
    private static Bowl bowl0 = new Bowl(0);

    static {
        Bowl bowl1 = new Bowl(1);
    }

    public CupBoard(){
        System.out.println("This is constructor");
    }

    private static Bowl bowl2 = new Bowl(2);

    private Bowl bowl4 = new Bowl(4);

    static {
        Bowl bowl3 = new Bowl(3);
    }

    public static void main(String[] args){
        CupBoard cupBoard = new CupBoard();
    }
}

Here's the output:

The constructor of Bowl invoked #0
The constructor of Bowl invoked #1
The constructor of Bowl invoked #2
The constructor of Bowl invoked #3
The constructor of Bowl invoked #4
This is constructor

Initialization Blocks

Instance initialization block code runs right after static initialization block, and the constructor runs at last. Here's an example:

public class Bowl {
    {
        System.out.println("Initialize Block Reached");
    }
    
    static {
        System.out.println("Staic Initialize Block Reached");
    }
    
    public static void main(String[] args) {
        Bowl bowl = new Bowl();
        bowl = new Bowl();
    }
    
    public Bowl() {
        System.out.println("The constructor of Bowl invoked");
    }
}

Here's the output

Staic Initialize Block Reached
Initialize Block Reached
The constructor of Bowl invoked
Initialize Block Reached
The constructor of Bowl invoked

Initialization Order for Classes with Inheritance

The general order of initialization for classes with inheritance is:

  • First, parent static items, then child static items
  • Then parent member variables, followed by the parent constructor
  • Then child member variables, followed by the child constructor
public class Bowl {
    public Bowl(int index) {
        System.out.println("The constructor of Bowl invoked #" + index);
    }
}

public class Base {
    static Bowl bowl0 = new Bowl(0);
    
    public Base() {
        Bowl bowl5 = new Bowl(5);
    }
    
    Bowl bowl4 = new Bowl(4);
    
    static {
        Bowl bowl1 = new Bowl(1);
        System.out.println("Static Blocks in Base.");
    }
}

public class Derived extends Base {
    static {
        Bowl bowl2 = new Bowl(2);
        System.out.println("Static Blocks in Derived.");
    }
    
    Bowl bowl6 = new Bowl(6);
    
    static Bowl bowl3 = new Bowl(3);
    
    public Derived() {
        Bowl bowl7 = new Bowl(7);
    }
}

public class CupBoard {
    public static void main(String[] args) {
        Derived derived = new Derived();
    }
}

Here's the output:

The constructor of Bowl invoked #0
The constructor of Bowl invoked #1
Static Blocks in Base.
The constructor of Bowl invoked #2
Static Blocks in Derived.
The constructor of Bowl invoked #3
The constructor of Bowl invoked #4
The constructor of Bowl invoked #5
The constructor of Bowl invoked #6
The constructor of Bowl invoked #7

Reference

  • http://blog.csdn.net/yangyan19870319/article/details/6202403
  • http://www.jusfortechies.com/java/core-java/static-blocks.php
  • http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ306_014.htm
Contact Us
  • SenseTime Research, Shenzhen Bay Eco-Technology Park
  • cshzxie [at] gmail [dot] com