new
— и все готово :) Здесь поговорим о том, что происходит внутри компьютера и Java-машины, когда мы пишем, например:
Cat cat = new Cat();
Мы ранее уже говорили об этом, но на всякий случай вспомним:
- Сначала для хранения объекта выделяется память.
- Далее Java-машина создает ссылку на этот объект (в нашем случае ссылка — это
Cat cat
). - В завершение происходит инициализация переменных и вызов конструктора (этот процесс мы рассмотрим подробнее).

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++;
}
}
Класс Truck
представляет собой реализацию грузовика: с полями, отражающими его год выпуска, модель и максимальную скорость.
Итак, мы хотим создать один такой объект:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
Вот как будет выглядеть этот процесс с точки зрения Java-машины:
Первое что произойдет — проинициализируются статические переменные класса
Car
. Да-да, именно классаCar
, а не Truck. Статические переменные инициализируются еще до вызова конструкторов, и начинается это в классе-родителе. Давай попробуем проверить. Выставим счетчикcarCounter
в классеCar
на 10 и попробуем вывести его в консоль в обоих конструкторах —Car
иTruck
.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++; } }
Мы специально поставили вывод в консоль в самом начале конструктора
Truck
, чтобы точно знать: поля грузовика на момент выводаcarCounter
’a в консоль еще не были инициализированы.А вот и результат:
10 10
После инициализации статических переменных класса-предка инициализируются статические переменные класса-потомка. То есть в нашем случае — поле
truckCounter
классаTruck
.Опять же, проведем эксперимент и попробуем вывести значение
truckCounter
’a внутри конструктораTruck
до инициализации остальных полей: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++; } }
Как видишь, значение 10 уже было присвоено нашей статической переменной на момент, когда конструктор
Truck
начал свою работу.Время конструкторов все еще не пришло! Инициализация переменных продолжается. Третьими по счету будут инициализированы нестатические переменные класса-предка. Как видишь, наследование заметно усложняет процесс создания объекта, но тут уж ничего не поделаешь: некоторые вещи в программировании придется просто запомнить :)
Для эксперимента мы можем присвоить переменной
description
классаCar
какое-то первоначальное значение, а потом поменять его в конструкторе.public class Car { public static int carCounter = 10; private String description = "Начальное значение поля description"; public Car() { System.out.println(description); description = "Абстрактная машина"; System.out.println(description); } public String getDescription() { return description; } }
Запустим наш метод
main()
с созданием грузовика:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }
И получим результат:
Начальное значение поля description Абстрактная машина
Это доказывает, что на момент начала работы конструктора
Car
у поляdescription
уже было присвоенное значение.Наконец, дело дошло до конструкторов! Точнее, до конструктора базового класса. Начало его работы — четвертый пункт в процессе создания объекта.
Проверить это тоже достаточно легко. Попробуем вывести в консоль две строки: одну внутри конструктора базового
Car
, вторую — внутри конструктораTruck
. Нам нужно убедиться, что строка внутриCar
выведется первой: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++; }
Запускаем наш метод
main()
и смотрим на результат:Привет из конструктора Car! Привет из конструктора Truck!
Отлично, значит мы не ошиблись :) Едем дальше.
Теперь пришла очередь инициализации нестатических полей класса-потомка, то есть нашего класса
Truck
. Поля класса, объект которого мы создаем, инициализируются только в пятую очередь! Удивительно, но факт :) Опять же, проведем простую проверку, такую же, как и с родительским классом: присвоим переменной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("Изначальное значение maxSpeed = " + this.maxSpeed); this.yearOfManufacture = yearOfManufacture; this.model = model; this.maxSpeed = maxSpeed; Car.carCounter++; truckCounter++; } }
Вывод в консоль:
Изначальное значение maxSpeed = 150
Как видишь, на момент старта конструктора
Truck
значениеmaxSpeed
уже было равно 150!Вызывается конструктор дочернего класса
Truck
.И только сейчас, в последнюю очередь, будет вызван конструктор того класса, объект которого мы создаем!
Только на шестом этапе полям будут присвоены те значения, которые мы передадим в качестве параметров нашему грузовику.
Как видишь, «конструирование» грузовика, т.е. процесс создания объекта — штука непростая. Но мы, кажется, разобрали его до самых мелочей :)

ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ