We 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).
These 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:
The first thing that happens is the static variables of the
Vehicleclass are initialized. Yes, I said theVehicleclass, notTruck. Static variables are initialized before constructors are called, and this starts in the parent class. Let's try to verify this. We set thevehicleCounterfield in theVehicleclass equal to 10 and try to display it in both theVehicleandTruckconstructors.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
Truckconstructor to be sure that the truck's fields haven't yet been initialized whenvehicleCounteris displayed.And here's the result:
10 10After the static variables of the parent class are initialized, the static variables of the child class are initialized. In our case, this is the
truckCounterfield of theTruckclass.Let's do another experiment where we'll try to display the value of
truckCounterinside theTruckconstructor 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
Truckconstructor begins.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
descriptionvariable inVehicleclass, 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 VehicleThis proves that when the
Vehicleconstructor begins thedescriptionfield has already been assigned a value.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
Vehiclebase class constructor, the second inside theTruckconstructor. We need to be convinced that the line insideVehicleis 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.
Now it's time for initialization of the non-static fields of the child class, i.e. our
Truckclass. 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 themaxSpeedvariable and in theTruckconstructor 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 = 150As you can see, when the
Truckconstructor starts,maxSpeedis already equal to 150!The constructor of the
Truckchild 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 :)
Why 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! :)
GO TO FULL VERSION