Initialization is the 3rd Step in ClassLoading Process. Initialization step happens in 2 steps.

  1. Class Initialization: First, all the static members(static variables, static initialization blocks, and static methods) are initialized ONLY ONCE
  2. Instance Initialization: Instance members(instance variables, instance initialization blocks, and instance methods) of the class are initialized every time a new object of the class is created.

Deep Dive into Instance Initialization

  • It starts from object creation using new keyword in Java, say
    • new A() - Default constructor
    • new A("val") - Overloaded constructor
  • If we don’t provide a constructor in our class, a default constructor is created by the javac compiler
    • Example

      class A {}
      

      Code generated by javac compiler

      class A {
        A() {
          super(); // Calls super class's constructor
        }
      }
      
  • And, always the super() is implicitly defined as the first line in your constructor(Default/Parameterized(Overloaded))
    • Example

      class A {
        A() {}
      }
      

      Code generated by javac compiler

      class A {
        A() {
          super(); // Implictly defined by the compiler
        }
      }
      
  • If we have defined an overloaded constructor, there wouldn’t be a default constructor created by compiler. And, super() is implicitly defined as the first line in your constructor(Default/Parameterized(Overloaded))

    • Example

      class A {
        A(int x) {}
      }
      

      Code generated by javac compiler

      class A {
        A(int x){
          super(); // Implicitly defined by the compiler
        }
      }
      
  • The key takeaways of instance initialization

    When a constructor(Default/overloaded) is invoked

    1. super() will be added by compiler in first line if it’s not explicitly declared.
      • This calls super class constructor
    2. Next, the instance initializer blocks in current class are scanned and executed in sequence

    3. Then the code in constructor gets executed

Initialization(Class+Instance) Step without Inheritance

Example:

import lombok.extern.slf4j.Slf4j;

@Slf4j
class A {
  static {
    log.info("1. In A's static block 1");
  }

  static {
    log.info("2. In A's static block 2");
  }

  {
    log.info("3. In A's instance block 1");
  }

  {
    log.info("4. In A's instance block 2");
  }

  A() {
    log.info("5. In A's default constructor");
  }
}

public class ClassInitializationDemo {

  public static void main(String[] args) {
    new A();
    new A();
  }
}

Output:

16:25:02.196 [main] INFO com.srk.gym.A -- 1. In A's static block 1
16:25:02.199 [main] INFO com.srk.gym.A -- 2. In A's static block 2
16:25:02.199 [main] INFO com.srk.gym.A -- 3. In A's instance block 1
16:25:02.199 [main] INFO com.srk.gym.A -- 4. In A's instance block 2
16:25:02.199 [main] INFO com.srk.gym.A -- 5. In A's default constructor
16:25:02.200 [main] INFO com.srk.gym.A -- 3. In A's instance block 1
16:25:02.200 [main] INFO com.srk.gym.A -- 4. In A's instance block 2
16:25:02.200 [main] INFO com.srk.gym.A -- 5. In A's default constructor

Inferences and Observations

  1. All static blocks are executed ONLY ONCE in the order in which they are declared irrespective of the number of objects created
  2. For each new A()
    • All the instance blocks are executed in sequence followed by its default constructor

Initialization(Class+Instance) Step with Inheritance

Example:

import lombok.extern.slf4j.Slf4j;

@Slf4j
class A {
  static {
    log.info("1. In A's static block 1");
  }

  static {
    log.info("2. In A's static block 2");
  }

  {
    log.info("5. In A's instance block 1");
  }

  {
    log.info("6. In A's instance block 2");
  }

  A() {
    log.info("7. In A's default constructor");
  }
}

@Slf4j
class B extends A {
  static {
    log.info("3. In B's static block 1");
  }

  static {
    log.info("4. In B's static block 2");
  }

  {
    log.info("8. In B's instance block 1");
  }

  {
    log.info("9. In B's instance block 2");
  }

  B() {
    log.info("10. In B's default constructor");
  }
}

public class ClassInitializationDemo {

  public static void main(String[] args) {
    new B();
    new B();
  }
}

Output:

13:50:26.908 [main] INFO com.srk.gym.A -- 1. In A's static block 1
13:50:26.910 [main] INFO com.srk.gym.A -- 2. In A's static block 2
13:50:26.910 [main] INFO com.srk.gym.B -- 3. In B's static block 1
13:50:26.910 [main] INFO com.srk.gym.B -- 4. In B's static block 2
13:50:26.910 [main] INFO com.srk.gym.A -- 5. In A's instance block 1
13:50:26.910 [main] INFO com.srk.gym.A -- 6. In A's instance block 2
13:50:26.910 [main] INFO com.srk.gym.A -- 7. In A's default constructor
13:50:26.910 [main] INFO com.srk.gym.B -- 8. In B's instance block 1
13:50:26.910 [main] INFO com.srk.gym.B -- 9. In B's instance block 2
13:50:26.910 [main] INFO com.srk.gym.B -- 10. In B's default constructor
13:50:26.910 [main] INFO com.srk.gym.A -- 5. In A's instance block 1
13:50:26.910 [main] INFO com.srk.gym.A -- 6. In A's instance block 2
13:50:26.910 [main] INFO com.srk.gym.A -- 7. In A's default constructor
13:50:26.910 [main] INFO com.srk.gym.B -- 8. In B's instance block 1
13:50:26.910 [main] INFO com.srk.gym.B -- 9. In B's instance block 2
13:50:26.910 [main] INFO com.srk.gym.B -- 10. In B's default constructor

Observations and Inferences

  1. One time execution of static members(static variables, static initialization blocks, and static methods) in Super class and subclass irrespective of the number of new B() are created.
  2. For each new B()
    • Super Class’s instance blocks are executed in sequence followed by its default constructor
    • And, Subclass instance blocks are executed in sequence followed by its default constructor


References:

  1. When to use instance initializers SO Answer
  2. Static vs Instance Initializers SO Answer