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
в консоль ще не були ініціалізовані.А ось і результат:
10 10
-
Після ініціалізації статичних змінних класу-предка ініціалізуються статичні змінні класу-нащадка. Тобто в нашому випадку – поле
truckCounter
класуTruck
.Знову ж таки, проведемо експеримент і спробуємо вивести значення
truckCounter
всередині конструктора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
.І тільки зараз, в останню чергу, буде викликано конструктор того класу, який ми створюємо!
Тільки на шостому етапі полям будуть присвоєні ті значення, які ми передамо як параметри нашій вантажівці.
Як бачиш, «конструювання» вантажівки, тобто. процес створення об'єкта – штука непроста. Але ми, здається, розібрали його до дрібниць :)
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ