Vi kommer att analysera det från början till slut: hur konstruktörer kallas, hur och i vilken ordning fält (inklusive statiska fält) initieras, etc. Vi har tidigare berört några av punkterna som diskuteras i artikeln, så att du kan titta över materialet på basklasskonstruktörer . Låt oss först komma ihåg hur ett objekt skapas. Du kommer väl ihåg hur den här processen ser ut ur en utvecklares synvinkel: han skapar en klass, skriver , newoch allt är klart :) Här ska vi prata om vad som händer inuti datorn och Java-maskinen när vi skriver, till exempel:
Cat cat = new Cat();
Vi har pratat om detta förut, men ifall vi ska påminna dig:
- Först tilldelas minne för att lagra objektet.
- Därefter skapar Java-maskinen en referens till objektet (i vårt fall är referensen Cat cat).
- Slutligen initieras variabler och konstruktorn anropas (vi ska titta på denna process mer i detalj).
Dessa två första punkter bör inte väcka några speciella frågor. Minnestilldelning är en enkel process, och det finns bara två möjliga resultat: antingen finns det minne eller så finns det inte :) Och att skapa en länk är inte ovanligt. Men den tredje punkten representerar en hel uppsättning operationer som utförs i strikt ordning. Jag är inte ett fan av att fylla på med tester, men du måste förstå denna process väl och du måste memorera den här operationssekvensen. När vi pratade om processen för att skapa objekt i tidigare lektioner visste du inte riktigt något om arv ännu, så att förklara vissa saker var problematiskt. Nu vet du ganska mycket och vi kan äntligen överväga denna fråga i sin helhet :) Så den tredje punkten säger " Äntligen initieras variabler och konstruktorn anropas. " Men i vilken ordning sker allt detta? För en bättre förståelse, låt oss skapa två superenkla klasser - en förälder och ett barn:
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++;
}
}
Klassen Truckär en implementering av en lastbil med fält som representerar dess år, modell och maxhastighet. Nu vill vi skapa ett sådant objekt:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
För Java-maskinen kommer processen att se ut så här:
-
Det första som händer är att klassens statiska variabler
Vehicleinitieras . Ja, jag saVehicleklassen, inteTruck. Statiska variabler initieras innan konstruktörer anropas, och detta börjar i den överordnade klassen. Låt oss försöka verifiera detta. Vi sättervehicleCounterfältet iVehicleklassen lika med 10 och försöker visa det i både konstruktörernaVehicleoch .Truckpublic 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++; } }Vi lägger medvetet println-satsen i början av konstruktören
Truckför att vara säker på att lastbilens fält ännu inte har initialiserats närvehicleCountervisas.Och här är resultatet:
10 10 -
Efter att de statiska variablerna för den överordnade klassen har initierats, initieras de statiska variablerna för den underordnade klassen. I vårt fall är detta
truckCounterklassens områdeTruck.Låt oss göra ett annat experiment där vi ska försöka visa värdet på
truckCounterinutiTruckkonstruktorn innan de andra fälten initieras: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++; } }Som du kan se har värdet 10 redan tilldelats vår statiska variabel när
Truckkonstruktorn börjar. -
Det är fortfarande inte dags för konstruktörerna! Variabel initiering fortsätter. De icke-statiska variablerna för moderklassen initieras tredje. Som du kan se komplicerar arv avsevärt processen att skapa ett objekt, men det finns inget du kan göra åt det: Du måste bara memorera några saker i programmering :)
Som ett experiment kan vi tilldela ett initialt värde till
descriptionvariabeln iVehicleklassen och sedan ändra det i konstruktorn.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; } }Låt oss köra vår
main()metod som skapar en lastbil:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }Vi får följande resultat:
Initial value of the description field VehicleDetta bevisar att när
Vehiclekonstruktören börjardescriptionhar fältet redan tilldelats ett värde. -
Äntligen är det dags för konstruktörerna! Mer exakt är det dags för basklasskonstruktören. Det anropas i det fjärde steget av objektskapandeprocessen.
Detta är också ganska lätt att verifiera. Låt oss försöka mata ut två rader till konsolen: en inuti basklasskonstruktorn,
Vehicleden andra inutiTruckkonstruktorn. Vi måste vara övertygade om att raden inutiVehiclevisas först: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++; }Vi kör vår
main()metod och tittar på resultatet:Hello from the Vehicle constructor! Hello from the Truck constructor!Excellent. Det betyder att vi inte har fel :) Låt oss gå vidare.
-
Nu är det dags för initialisering av de icke-statiska fälten i barnklassen, dvs vår
Truckklass. Fälten omedelbart inom klassen som instansieras initieras inte förrän i det femte steget! Överraskande, men sant :) Återigen, vi kommer att göra en enkel kontroll — precis som med den överordnade klassen: vi skaffar ett initialvärde till variabelnmaxSpeedoch iTruckkonstruktorn kontrollerar vi att värdet tilldelades innan konstruktorn startade: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++; } }Konsolutgång:
Initial value of maxSpeed = 150Som du kan se, när
Truckkonstruktören startar,maxSpeedär redan lika med 150! -
Konstruktören av
Truckbarnklassen kallas.Och först vid denna tidpunkt, sist av allt, kommer konstruktören av klassen vi instansierar att kallas!
Först i det sjätte steget kommer fälten att tilldelas de värden som vi skickar som argument till vår lastbil.
Som du kan se är det inte enkelt att "konstruera" en lastbil, dvs processen för att skapa objekt. Men det verkar som att vi har delat upp det i de minsta delarna :)
Varför är det så viktigt att förstå denna process väl? Föreställ dig hur oväntat resultatet av att skapa ett vanligt föremål kan bli om du inte visste exakt vad som hände "under huven" :) Nu är det dags att återvända till kursen och slutföra några uppgifter! Lycka till och vi ses snart! :)
GO TO FULL VERSION