Hi! Last time we talked about constructors and learned a lot about them. Now we're going to talk about base class constructors.
Base class constructors   - 1
What's a base class? It has to do with the fact that in Java several different classes can have a common origin.
Base class constructors   - 2
This is called inheritance. Several child classes can have one common ancestor. For example, imagine that we have an Animal class:
public class Animal {

   String name;
   int age;
}
We can declare 2 child classes: Cat and Dog. This is done using the keyword extends.
public class Cat extends Animal {

}

public class Dog extends Animal {

}
We may find this helpful in the future. For example, if there is a task to catch mice, we'll create a Cat object in our program. If the task is to chase after a stick, then we'll use a Dog object. And if we create a program that simulates a veterinary clinic, it will work with the Animal class (and thus be able to treat both cats and dogs). It is very important to remember that when an object is created, the constructor of its base class is first called. Only after that constructor is finished does the program execute the constructor of the class corresponding to the object we are creating. In other words, when creating a Cat object, the Animal constructor is run first, and only afterward is the Cat constructor executed. To see this, add some console output to the Cat and Animal constructors.
public class Animal {

   public Animal() {
       System.out.println("Animal constructor executed");
   }
}


public class Cat extends Animal {

   public Cat() {
       System.out.println("Cat constructor executed!");
   }

   public static void main(String[] args) {
       Cat cat = new Cat();
   }
}
Console output: Animal constructor executed Cat constructor executed! Indeed, it does work that way! Why? One reason is to avoid duplicating fields shared between the two classes. For example, every animal has a heart and brain, but not every animal has a tail. We could declare brain and heart fields, which are common to all animals, in the Animal parent class, and a tail field in the Cat subclass. . Now we'll declare a Cat class constructor that takes arguments for all 3 fields.
public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Note: The constructor works correctly even though the Cat class has no brain and heart fields. These fields are "inherited" from the Animal base class. The inheriting class has access to the fields of the base class, so they are visible in our Cat class. As a result, we don't need to duplicate these fields in the Cat class. We can take them from the Animal class. What's more, we can explicitly call the base class constructor in the child class constructor. A base class is also called a "superclass". That's why Java uses the keyword super to indicate the base class. In the previous example
public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }
We separately assigned each field in our parent class. We don't actually have to do this. It's enough to call the parent class constructor and pass the necessary arguments:
public class Animal {

   String brain;
   String heart;

   public Animal(String brain, String heart) {
       this.brain = brain;
       this.heart = heart;
   }

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
In the Cat constructor, we called the Animal constructor and passed two fields. We had only one field to explicitly initialize: tail, which is not in Animal. Remember we mentioned that the parent class constructor is called first when an object is created? That's why super() should always be first in a constructor! Otherwise, the constructor logic will be violated and the program will generate an error.
public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.tail = tail;
       super(brain, heart);// Error!
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
The compiler knows that when an object of a child class is created, the base class constructor is called first. And if you try to manually change this behavior, the compiler won't allow it.

How an object is created

We previously looked at an example with a base and parent class: Animal and Cat. Using these two classes as examples, we'll now look at the process of creating an object and initializing variables. We know that there are static and instance (non-static) variables. We also know that the Animal base class has variables, and the Cat child class has its own. For clarity, we'll add one static variable each to the Animal and Cat classes. The animalCount variable in the Animal class will represent the total number of animal species on Earth, and the catCount variable will signify the number of cat species. Additionally, we'll assign starting values to all non-static variables in both classes (which will then be changed in the constructor).
public class Animal {

   String brain = "Initial value of brain in the Animal class";
   String heart = "Initial value of heart in the Animal class";

   public static int animalCount = 7700000;

   public Animal(String brain, String heart) {
       System.out.println("Animal base class constructor is running");
       System.out.println("Have the variables of the Animal class already been initialized?");
       System.out.println("Current value of static variable animalCount = " + animalCount);
       System.out.println("Current value of brain in the Animal class = " + this.brain);
       System.out.println("Current value of heart in the Animal class = " + this.heart);
       System.out.println("Have the variables of the Cat class already been initialized?");
       System.out.println("Current value of static variable catCount = " + Cat.catCount);

       this.brain = brain;
       this.heart = heart;
       System.out.println("Animal base class constructor is done!");
       System.out.println("Current value of brain = " + this.brain);
       System.out.println("Current value of heart = " + this.heart);
   }
}

public class Cat extends Animal {

   String tail = "Initial value of tail in the Cat class";

   static int catCount = 37;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       System.out.println("The cat class constructor has started (The Animal constructor already finished)");
       System.out.println("Current value of static variable catCount = " + catCount);
       System.out.println("Current value of tail = " + this.tail);
       this.tail = tail;
       System.out.println("Current value of tail = " + this.tail);
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
So we're creating a new instance of the Cat class, which inherits Animal. We've added some detailed console output to see what's happening and in what order. This is what will be displayed when a Cat object is created: Animal base class constructor is running Have the variables of the Animal class already been initialized? Current value of static variable animalCount = 7700000 Current value of brain in the Animal class = Initial value of brain in the Animal class Current value of heart in the Animal class = Initial value of heart in the Animal class Have the variables of the Cat class already been initialized? Current value of static variable catCount = 37 Animal base class constructor is done! Current value of brain = Brain Current value heart = Heart The cat class constructor has started (The Animal constructor already finished) Current value of static variable catCount = 37 Current value of tail = Initial value of tail in the Cat class Current value of tail = Tail So, now we can clearly see the order of variable initialization and constructor calls when a new object is created:
  1. Static variables of the base class (Animal) are initialized. In our case, the Animal class's variable animalCount is set to 7700000.

  2. Static variables of the child class (Cat) are initialized.

    Note: we're still inside the Animal constructor and we've already displayed:

    Animal base class constructor is running
    Have the variables of the Animal class already been initialized?
    Current value of static variable animalCount = 7700000
    Current value of brain in the Animal class = Initial value of brain in the Animal class
    Current value of heart in the Animal class = Initial value of heart in the Animal class
    Have the variables of the Cat class already been initialized?
    Current value of static variable catCount = 37


  3. Then the non-static variables of the base class are initialized. We specifically assigned them initial values, which are then replaced in the constructor. The Animal constructor has not finished yet, but the initial values of brain and heart have already been assigned:

    Animal base class constructor is running
    Have the variables of the Animal class already been initialized?
    Current value of static variable animalCount = 7700000
    Current value of brain in the Animal class = Initial value of brain in the Animal class
    Current value of heart in the Animal class = Initial value of heart in the Animal class


  4. The base class constructor starts.
    We've already convinced ourselves that this step is fourth: in the first three steps at the beginning of the Animal constructor, many variables have already been assigned values.


  5. Non-static fields of the child class (Cat) are initialized.
    This happens before the Cat constructor starts running.
    When it starts running, the tail variable already has a value:

    The cat class constructor has started (The Animal constructor already finished) Current value of static variable catCount = 37 Current value of tail = Initial value of tail in the Cat class


  6. The constructor of the Cat child class is called

    And that's what creating an object looks like in Java!

    I must say that we are not big fans of rote-learning, but it's best to memorize the order of variable initialization and constructor calls.

    This will greatly increase your understanding of the flow of the program, and the state of your objects at any particular moment.

    Moreover, many classes don't use inheritance. In this case, the steps related to the base class don't apply.