new
и всичко е готово :) Тук ще говорим Howво се случва вътре в компютъра и Java машината, когато пишем, например:
Cat cat = new Cat();
Говорor сме за това и преди, но за всеки случай ще ви напомним:
- Първо се разпределя памет за съхраняване на обекта.
- След това Java машината създава препратка към обекта (в нашия случай препратката е Cat cat).
- Накрая се инициализират променливите и се извиква конструкторът (ще разгледаме този процес по-подробно).
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++;
}
}
Класът Truck
е реализация на камион с полета, представляващи неговата година, модел и максимална скорост. Сега искаме да създадем един такъв обект:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
За Java машината процесът ще изглежда така:
-
Първото нещо, което се случва е, че статичните променливи на
Vehicle
класа се инициализират . Да, казахVehicle
класа, неTruck
. Статичните променливи се инициализират преди извикването на конструкторите и това започва в родителския клас. Нека се опитаме да проверим това. ЗадавамеvehicleCounter
полето вVehicle
класа равно на 10 и се опитваме да го покажем Howто в конструкторите,Vehicle
така и вTruck
конструкторите.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++; } }
Съзнателно поставихме оператора println в самото начало на
Truck
конструктора, за да сме сигурни, че полетата на камиона все още не са инициализирани, когатоvehicleCounter
се показва .И ето резултата:
10 10
-
След инициализиране на статичните променливи на родителския клас, статичните променливи на дъщерния клас се инициализират. В нашия случай това е
truckCounter
полето наTruck
класа.Нека направим друг експеримент, при който ще се опитаме да покажем стойността на
truckCounter
вътре вTruck
конструктора, преди другите полета да бъдат инициализирани: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++; } }
Както можете да видите, стойността 10 вече е присвоена на нашата статична променлива, когато
Truck
конструкторът започне. -
Все още не е време за конструкторите! Инициализацията на променливата продължава. Нестатичните променливи на родителския клас се инициализират трети. Както можете да видите, наследяването значително усложнява процеса на създаване на обект, но нищо не можете да направите по въпроса: просто трябва да запомните някои неща в програмирането :)
Като експеримент можем да присвоим няHowва първоначална стойност на
description
променливата вVehicle
класа и след това да я променим в конструктора.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; } }
Нека стартираме нашия
main()
метод, който създава камион:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }
Получаваме следния резултат:
Initial value of the description field Vehicle
Това доказва, че когато
Vehicle
конструкторът започне, наdescription
полето вече е присвоена стойност. -
Най-накрая дойде време за конструкторите! По-точно, време е за конструктора на базов клас. Той се извиква в четвъртата стъпка от процеса на създаване на обект.
Това също е доста лесно да се провери. Нека опитаме да изведем два реда към конзолата: единият вътре в
Vehicle
конструктора на базовия клас, вторият вътре вTruck
конструктора. Трябва да сме убедени, че редът вътреVehicle
се показва първо: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++; }
Ще изпълним нашия
main()
метод и ще видим резултата:Hello from the Vehicle constructor! Hello from the Truck constructor!
Отлично. Това означава, че не сме сбъркали :) Да продължим.
-
Сега е време за инициализация на нестатичните полета на дъщерния клас, т.е. на нашия
Truck
клас. Полетата непосредствено в инстанцирания клас не се инициализират до петата стъпка! Изненадващо, но вярно :) Отново ще направим проста проверка — точно Howто с родителския клас: ще зададем няHowва начална стойност на променливатаmaxSpeed
и вTruck
конструктора ще проверим дали стойността е била присвоена преди стартирането на конструктора: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++; } }
Конзолен изход:
Initial value of maxSpeed = 150
Както можете да видите, когато
Truck
конструкторът стартира,maxSpeed
вече е равно на 150! -
Truck
Извиква се конструкторът на дъщерния клас.И едва в този момент, на последно място, ще бъде извикан конструкторът на класа, който инстанцираме!
Само в шестата стъпка на полетата ще бъдат присвоени стойностите, които предаваме като аргументи на нашия камион.
Както можете да видите, "конструирането" на камион, т.е. процесът на създаване на обект, не е лесен. Но изглежда, че сме го разделor на най-малки части :)
GO TO FULL VERSION