Sequence of actions during object creation

Published in the Java Developer group
Hi! Today's lesson will be quite... uh... multifaceted :) in the sense that we will cover a wide range of topics, but they will all relate to the object creation process. Sequence of actions during object creation - 1We will analyze it from beginning to end: how constructors are called, how and in what order fields (including static fields) are initialized, etc. We've previously touched on some of the points discussed in the article, so you can glance over the material on base class constructors. First, let's recall how an object is created. You well remember how this process looks from a developer's point of view: he creates a class, writes new, and everything is ready :) Here we'll talk about what happens inside the computer and the Java machine when we write, for example:

Cat cat = new Cat();
We've talked about this before, but just in case we'll remind you:
  • First, memory for storing the object is allocated.
  • Next, the Java machine creates a reference to the object (in our case the reference is Cat cat).
  • Finally, variables are initialized and the constructor is called (we're going to look at this process in more detail).
In addition, from the lesson on the object life cycle, you probably remember that an object lasts as long as there is at least one reference to it. If there are none left, then the object becomes prey for the garbage collector. Sequence of actions during object creation - 2These first two points should not raise any special questions. Memory allocation is a simple process, and there are only two possible outcomes: either there is memory or there is not :) And creating a link is not unusual. But the third point represents a whole set of operations executed in strict order. I'm not a fan of cramming for tests, but you need to understand this process well and you need to memorize this sequence of operations. When we talked about the object creation process in previous lessons, you didn't really know anything about inheritance yet, so explaining some things was problematic. Now you know quite a lot and we can finally consider this question in full :) So the third point says "Finally, variables are initialized and the constructor is called." But what order does all this happen in? For a better understanding, let's create two super simple classes — a parent and a child:

public class Vehicle { 

   public static int vehicleCounter = 0; 

   private String description = "Vehicle"; 
   public Vehicle() { 
   } 

   public String getDescription() { 
       return description; 
   } 
} 

public class Truck extends Vehicle { 

   private static int truckCounter = 0; 

   private int yearOfManufacture; 
   private String model; 
   private int maxSpeed; 

   public Truck(int yearOfManufacture, String model, int maxSpeed) { 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 

       Vehicle.vehicleCounter++; 
       truckCounter++; 
   } 
}
The Truck class is an implementation of a truck with fields representing its year, model, and maximum speed. Now we want to create one such object:

public class Main { 

   public static void main(String[] args) throws IOException { 

       Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
   } 
}
To the Java machine, the process will look like this:
  1. The first thing that happens is the static variables of the Vehicle class are initialized. Yes, I said the Vehicle class, not Truck. Static variables are initialized before constructors are called, and this starts in the parent class. Let's try to verify this. We set the vehicleCounter field in the Vehicle class equal to 10 and try to display it in both the Vehicle and Truck constructors.

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
       private String description = "Vehicle"; 
    
       public Vehicle() { 
           System.out.println(vehicleCounter); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    } 
    
    public class Truck extends Vehicle { 
    
       private static int truckCount = 0;
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(vehicleCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCount++; 
       } 
    }
    

    We deliberately put the println statement at the very beginning of the Truck constructor to be sure that the truck's fields haven't yet been initialized when vehicleCounter is displayed.

    And here's the result:

    
    10 
    10
    
  2. After the static variables of the parent class are initialized, the static variables of the child class are initialized. In our case, this is the truckCounter field of the Truck class.

    Let's do another experiment where we'll try to display the value of truckCounter inside the Truck constructor before the other fields are initialized:

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(truckCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }
    

    As you can see, the value 10 has already been assigned to our static variable when the Truck constructor begins.

  3. It's still not time for the constructors! Variable initialization continues. The non-static variables of the parent class are initialized third.  As you can see, inheritance significantly complicates the process of creating an object, but there's nothing you can do about it: You just have to memorize some things in programming :)

    As an experiment, we can assign some initial value to the description variable in Vehicle class, and then change it in the constructor.

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
    
       private String description = "Initial value of the description field"; 
    
       public Vehicle() { 
           System.out.println(description); 
           description = "Vehicle"; 
           System.out.println(description); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    }
    

    Let's run our main() method that creates a truck:

    
    public class Main { 
    
       public static void main(String[] args) throws IOException { 
    
           Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
       } 
    }
    

    We get the following result:

    
    Initial value of the description field 
    Vehicle
    

    This proves that when the Vehicle constructor begins the description field has already been assigned a value.

  4. Finally, it is time for the constructors! More precisely, it is time for the base class constructor. It is invoked in the fourth step of the object creation process.

    This is also fairly easy to verify. Let's try outputting two lines to the console: one inside the Vehicle base class constructor, the second inside the Truck constructor. We need to be convinced that the line inside Vehicle is displayed first:

    
    public Vehicle() { 
    
       System.out.println("Hello from the Vehicle constructor!"); 
    } 
    
    public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
       System.out.println("Hello from the Truck constructor!"); 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 
    
       Vehicle.vehicleCounter++; 
       truckCounter++; 
    }
    

    We'll run our main() method and look at the result:

    
    Hello from the Vehicle constructor! 
    Hello from the Truck constructor! 
    

    Excellent. That means we're not mistaken :) Let's move on.

  5. Now it's time for initialization of the non-static fields of the child class, i.e. our Truck class. The fields immediately within the class being instantiated are not initialized until the fifth step! Surprising, but true :) Again, we'll do a simple check — just like with the parent class: we'll some initial value to the maxSpeed variable and in the Truck constructor we'll check that the value was assigned before the constructor started:

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed = 150; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
           System.out.println("Initial value of maxSpeed = " + this.maxSpeed); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }
    

    Console output:

    
    Initial value of maxSpeed = 150
    

    As you can see,  when the Truck constructor starts, maxSpeed is already equal to 150!

  6. The constructor of the Truck child class is called.

    And only at this point, last of all, will the constructor of the class we are instantiating be called!

    Only in the sixth step will the fields be assigned the values that we pass as arguments to our truck.

    As you can see, "constructing" a truck, i.e. the object creation process, is not simple. But it seems that we've broken it down into the smallest parts :)

Sequence of actions during object creation - 3Why is it so important to understand this process well? Imagine how unexpected the results of creating an ordinary object could be if you didn't know exactly what was happening "under the hood" :) Now it's time to return to the course and complete some tasks! Good luck and see you soon! :)
Comments (14)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Tasmoda Level 22, Midrand, South Africa
21 June 2022
Great article as always. Big up fam!🤙
proegg123 Level 16, Slovakia
21 March 2022
great :) thanks for the explanation, this is really helpful
Stanislav Mayer Level 15, Czech Republic
11 March 2022
Me trying to visualize / memorize the order :) Static variables Non-static variables Constructor Parent class 1. 3. 4. Child class 2. 5. 6.
Jonaskinny Level 25, Redondo Beach, United States
3 March 2022
Bob extends Person { private Person person = new Person(); } Person { private Bob bob = new Bob(); }
Gellert Varga Level 23, Szekesfehervar, Hungary
7 April 2021
I assume that the order in which a new object is created is as follows: 1) It starts by creating the variables in the child class, and going up on the inheritance chain from the bottom to the top through all parent classes all the way to the Object class, creating and setting all the variables in all classes to default (to zeros and to null-s) (both static and non-static!) (The child class instance variables already exist and store default values at that moment when the JVM is still working in the parent class constructor! We'll face this in the Task-1526 [debug, debug].) 2) in the parent classes, going down on the inheritance chain, initializing the static variables to the values ​​given in the code and executing static blocks. In the order of occurrence in the code. Finally, it does the same things in the child class at the very bottom of the chain. 3) in the parent classes, going down the inheritance chain, it does the following in each class: a) initializes all the instance variable to the values ​​specified in the code and executes the non-static blocks. (This is not the constructor!) In the order of occurrence in the code. b) after all of this, executes the constructor. In the end, it also does all of this inside the child class at the bottom of the chain. When we'll create already the second or the umpteenth object from the same class, point 2 is skipped.
Chang You Level 41, Santa Rosa, United States
25 December 2020
I think it'll be even better to print all the check-statement together instead of print one of them in each step, in this way the sequence will be more clear.
Banak Level 29, Saint-Gratien, France
8 December 2020
Super Super pour un profane à maîtriser par cour !
Andrei Level 41
7 December 2020
Wow, such a detailed explanation, very difficult topic (in my opinion) but made understandable by the wonderful explaining and breaking down of it. Thank you, great article!
Peter Schrijver Level 23, Hilversum, Netherlands
14 July 2020
This is gold. Very informative and nice to read. This is stored in my mind from now on.
WIDMO Level 41, Gdańsk, Poland
25 April 2020
Good job, but I was wondering what happens when the base class has also it's own base class? Let's consider 3 classes: class Animal, class Cat extends Animal, and class Tiger extends Cat . I guess that that process of creation will look: 1. Static variables ( in order: Animal, Cat, Tiger) 2. Pairs of {non-static vars and then contructor} ( in order: Animal, Cat Tiger) am I right?