O vom analiza de la început până la sfârșit: cum sunt chemați constructorii, cum și în ce ordine sunt inițializate câmpurile (inclusiv câmpurile statice) etc. Am atins anterior câteva dintre punctele discutate în articol, astfel încât să puteți arunca o privire peste materialul pe constructorii clasei de bază . Mai întâi, să ne amintim cum este creat un obiect. Vă amintiți bine cum arată acest proces din punctul de vedere al unui dezvoltator: el creează o clasă, scrie newși totul este gata :) Aici vom vorbi despre ce se întâmplă în interiorul computerului și a mașinii Java când scriem, de exemplu:
Cat cat = new Cat();
Am mai vorbit despre asta, dar în caz că vă reamintim:
- În primul rând, este alocată memoria pentru stocarea obiectului.
- Apoi, mașina Java creează o referință la obiect (în cazul nostru referința este Cat cat).
- În cele din urmă, variabilele sunt inițializate și constructorul este apelat (vom analiza acest proces mai detaliat).
Aceste prime două puncte nu ar trebui să ridice întrebări speciale. Alocarea memoriei este un proces simplu și există doar două rezultate posibile: fie există memorie, fie nu există :) Și crearea unei legături nu este neobișnuită. Dar al treilea punct reprezintă un întreg set de operații executate în ordine strictă. Nu sunt un fan al înghesuirii pentru teste, dar trebuie să înțelegeți bine acest proces și trebuie să memorați această secvență de operații. Când am vorbit despre procesul de creare a obiectelor în lecțiile anterioare, încă nu știai nimic despre moștenire, așa că explicarea unor lucruri a fost problematică. Acum știți destul de multe și în sfârșit putem lua în considerare această întrebare în întregime :) Deci, al treilea punct spune „ În sfârșit, variabilele sunt inițializate și constructorul este numit. ” Dar în ce ordine se întâmplă toate acestea? Pentru o mai bună înțelegere, să creăm două clase super simple — un părinte și un copil:
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++;
}
}
Clasa Truckeste o implementare a unui camion cu câmpuri care reprezintă anul, modelul și viteza maximă. Acum vrem să creăm un astfel de obiect:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
Pentru mașina Java, procesul va arăta astfel:
-
Primul lucru care se întâmplă este că variabilele statice ale
Vehicleclasei sunt inițializate . Da, am spusVehicleclasa, nuTruck. Variabilele statice sunt inițializate înainte ca constructorii să fie apelați, iar aceasta începe în clasa părinte. Să încercăm să verificăm acest lucru. SetămvehicleCountercâmpul dinVehicleclasă egal cu 10 și încercăm să îl afișam atât în constructori,Vehiclecât șiTruckîn constructori.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++; } }Am pus în mod deliberat instrucțiunea println chiar la începutul constructorului
Truckpentru a ne asigura că câmpurile camionului nu au fost încă inițializate cândvehicleCountereste afișată.Și iată rezultatul:
10 10 -
După ce variabilele statice ale clasei părinte sunt inițializate, variabilele statice ale clasei fii sunt inițializate. În cazul nostru, acesta este
truckCounterdomeniul claseiTruck.Să facem un alt experiment în care vom încerca să afișăm valoarea din
truckCounterinteriorulTruckconstructorului înainte ca celelalte câmpuri să fie inițializate: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++; } }După cum puteți vedea, valoarea 10 a fost deja atribuită variabilei noastre statice când
Truckîncepe constructorul. -
Inca nu este timpul pentru constructori! Inițializarea variabilei continuă. Variabilele non-statice ale clasei părinte sunt inițializate al treilea. După cum puteți vedea, moștenirea complică semnificativ procesul de creare a unui obiect, dar nu puteți face nimic în acest sens: trebuie doar să memorați câteva lucruri în programare :)
Ca experiment, putem atribui o valoare inițială variabilei
descriptiondinVehicleclasă și apoi o putem schimba în 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; } }Să rulăm
main()metoda noastră care creează un camion:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }Obtinem urmatorul rezultat:
Initial value of the description field VehicleAcest lucru demonstrează că atunci când
Vehicleconstructorul începedescriptioncâmpul i s-a atribuit deja o valoare. -
În sfârșit, este timpul pentru constructori! Mai precis, este timpul pentru constructorul clasei de bază. Este invocat în a patra etapă a procesului de creare a obiectului.
Acest lucru este, de asemenea, destul de ușor de verificat. Să încercăm să scoatem două linii în consolă: una în
Vehicleconstructorul clasei de bază, a doua în interiorulTruckconstructorului. Trebuie să fim convinși că linia din interiorVehicleeste afișată mai întâi: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++; }Vom rula
main()metoda noastră și ne vom uita la rezultat:Hello from the Vehicle constructor! Hello from the Truck constructor!Excelent. Asta înseamnă că nu ne înșelim :) Să mergem mai departe.
-
Acum este timpul pentru inițializarea câmpurilor non-statice ale clasei copil, adică
Truckclasa noastră. Câmpurile imediat din clasa instanțiată nu sunt inițializate până la pasul al cincilea! Surprinzător, dar adevărat :) Din nou, vom face o verificare simplă - la fel ca în cazul clasei părinte: vom da o valoare inițială variabileimaxSpeedși înTruckconstructor vom verifica dacă valoarea a fost atribuită înainte de a începe constructorul: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++; } }Ieșire din consolă:
Initial value of maxSpeed = 150După cum puteți vedea, când
Truckpornește constructorul,maxSpeedeste deja egal cu 150! -
Constructorul
Truckclasei copil este numit.Și numai în acest moment, în sfârșit, va fi numit constructorul clasei pe care o instanțiem!
Numai în pasul al șaselea câmpurilor li se vor atribui valorile pe care le transmitem ca argumente camionului nostru.
După cum puteți vedea, „construirea” unui camion, adică procesul de creare a obiectelor, nu este simplă. Dar se pare că l-am împărțit în cele mai mici părți :)
De ce este atât de important să înțelegem bine acest proces? Imaginați-vă cât de neașteptate ar putea fi rezultatele creării unui obiect obișnuit dacă nu știați exact ce se întâmplă „sub capotă” :) Acum este timpul să reveniți la curs și să finalizați câteva sarcini! Succes și ne vedem curând! :)
GO TO FULL VERSION