new
- and you're done :) Here we'll talk about what happens inside a computer and a Java machine when we write, for example:
Cat cat = new Cat();
We've talked about this before, but just in case, remember:
- First, memory is allocated to store the object.
- Next, the Java machine creates a link to this object (in our case, the link is
Cat cat
). - At the end, the variables are initialized and the constructor is called (we will consider this process in more detail).
public class Car {
public static int carCounter = 0;
private String description = "Абстрактная машина";
public Car() {
}
public String getDescription() {
return description;
}
}
public class Truck extends Car {
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;
Car.carCounter++;
truckCounter++;
}
}
The class Truck
is an implementation of a truck: with fields reflecting its year of manufacture, model, and maximum speed. So 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);
}
}
Here is how this process will look from the point of view of the Java machine:
-
The first thing that happens is that the static class variables are initialized
Car
. Yes, yes, exactly the classCar
, not the Truck . Static variables are initialized before constructors are called, and this begins in the parent class. Let's try to check. Let's set the countercarCounter
in the classCar
to 10 and try to output it to the console in both constructors -Car
andTruck
.public class Car { public static int carCounter = 10; private String description = "Абстрактная машина"; public Car() { System.out.println(carCounter); } public String getDescription() { return description; } } public class Truck extends Car { 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(carCounter); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Car.carCounter++; truckCount++; } }
We deliberately put the output to the console at the very beginning of the constructor
Truck
in order to know for sure: the truck fieldscarCounter
had not yet been initialized at the time 'a was output to the console.And here is the result:
10 10
-
After the static variables of the ancestor class are initialized, the static variables of the child class are initialized. That is, in our case, a
truckCounter
class fieldTruck
.Again, let's experiment and try to output the value of
truckCounter
'a inside the constructorTruck
before the rest of the fields are initialized:public class Truck extends Car { 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; Car.carCounter++; truckCounter++; } }
As you can see, the value 10 was already assigned to our static variable when the constructor
Truck
started its work. -
The time of designers has not come yet! Variable initialization continues. The third in a row will be initialized non-static variables of the ancestor class. As you can see, inheritance significantly complicates the process of creating an object, but there's nothing you can do about it: some things in programming you just have to remember :)
For the experiment, we can assign some initial value to
description
a class variable, and then change it in the constructor.Car
public class Car { public static int carCounter = 10; private String description = "Начальное meaning поля description"; public Car() { System.out.println(description); description = "Абстрактная машина"; System.out.println(description); } public String getDescription() { return description; } }
Let's run our method
main()
with the creation of a truck:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }
And we get the result:
Начальное meaning поля description Абстрактная машина
Car
This proves that the fielddescription
already had a value assigned when the constructor started . -
Finally, it came to the designers! More precisely, to the base class constructor. The beginning of its work is the fourth point in the process of creating an object.
It's easy enough to check this too. Let's try to output two lines to the console: one inside the base constructor
Car
, and the second inside the constructorTruck
. We need to make sure the line insideCar
is printed first:public Car() { System.out.println("Привет из конструктора Car!"); } public Truck(int yearOfManufacture, String model, int maxSpeed) { System.out.println("Привет из конструктора Truck!"); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Car.carCounter++; truckCounter++; }
We run our method
main()
and look at the result:Привет из конструктора Car! Привет из конструктора Truck!
Great, so we weren't mistaken :) Let's move on.
-
Now it's the turn to initialize the non-static fields of the child class , that is, our class
Truck
. The fields of the class whose object we are creating are only initialized in the fifth order! Surprising, but true :) Again, let's do a simple check, the same as with the parent class: assign some initial value to the variable and check in the constructor that it was assigned before the constructor started work:maxSpeed
Truck
public class Truck extends Car { 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("Изначальное meaning maxSpeed = " + this.maxSpeed); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Car.carCounter++; truckCounter++; } }
Console output:
Изначальное meaning maxSpeed = 150
As you can see, at the moment the constructor started,
Truck
the valuemaxSpeed
was already equal to 150! -
The constructor of the child class is called
Truck
.And only now, lastly, the constructor of the class whose object we are creating will be called!
Only at the sixth stage, the fields will be assigned the values that we will pass as parameters to our truck.
As you can see, the "design" of the truck, i.e. the process of creating an object is not an easy thing. But we seem to have dismantled it to the smallest detail :)