Animal
klasse:
public class Animal {
String name;
int age;
}
Vi kan erklære 2 børneklasser: Cat
og Dog
. Dette gøres ved at bruge nøgleordet extends .
public class Cat extends Animal {
}
public class Dog extends Animal {
}
Vi kan finde dette nyttigt i fremtiden. For eksempel, hvis der er en opgave at fange mus, opretter vi et Cat
objekt i vores program. Hvis opgaven er at jagte en pind, så bruger vi en Dog
genstand. Og hvis vi laver et program, der simulerer en dyrlægeklinik, vil det fungere sammen med Animal
klassen (og dermed kunne behandle både katte og hunde). Det er meget vigtigt at huske, at når et objekt oprettes, kaldes konstruktøren af dets basisklasse først . Først efter at denne konstruktør er færdig, udfører programmet konstruktøren af den klasse, der svarer til det objekt, vi opretter. Med andre ord, når du opretter et Cat
objekt, køres konstruktøren først ,Animal
og først bagefter køresCat
konstruktør udført . For at se dette skal du tilføje noget konsoloutput til Cat
og Animal
konstruktørerne.
public class Animal {
public Animal() {
System.out.println("Animal constructor executed");
}
}
public class Cat extends Animal {
public Cat() {
System.out.println("Cat constructor executed!");
}
public static void main(String[] args) {
Cat cat = new Cat();
}
}
Konsoludgang: Dyrekonstruktør udført Kattekonstruktør udført! Det virker faktisk sådan! Hvorfor? En grund er at undgå at duplikere felter, der deles mellem de to klasser. For eksempel har hvert dyr et hjerte og en hjerne, men ikke alle dyr har en hale. Vi kunne erklære hjerne- og hjertefelter , som er fælles for alle dyr, i forældreklassen Animal
og et halefelt i Cat
underklassen. . Nu vil vi erklære en Cat
klassekonstruktør, der tager argumenter for alle 3 felter.
public class Cat extends Animal {
String tail;
public Cat(String brain, String heart, String tail) {
this.brain = brain;
this.heart = heart;
this.tail = tail;
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
Bemærk: Konstruktøren fungerer korrekt, selvom klassen Cat
ikke har nogen hjerne- og hjertefelter . Disse felter er "arvet" fra Animal
basisklassen. Den nedarvede klasse har adgang til felterne i basisklassen , så de er synlige i vores Cat
klasse. Som et resultat behøver vi ikke at duplikere disse felter i Cat
klassen. Vi kan tage dem fra Animal
klassen. Hvad mere er, kan vi eksplicit kalde basisklassekonstruktøren i børneklassekonstruktøren. En basisklasse kaldes også en " superklasse ". Det er derfor, Java bruger søgeordet super til at angive basisklassen. I det foregående eksempel
public Cat(String brain, String heart, String tail) {
this.brain = brain;
this.heart = heart;
this.tail = tail;
}
Vi tildelte hvert felt separat i vores forældreklasse. Vi behøver faktisk ikke gøre dette. Det er nok at kalde den overordnede klassekonstruktør og sende de nødvendige argumenter:
public class Animal {
String brain;
String heart;
public Animal(String brain, String heart) {
this.brain = brain;
this.heart = heart;
}
public class Cat extends Animal {
String tail;
public Cat(String brain, String heart, String tail) {
super(brain, heart);
this.tail = tail;
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
I Cat
konstruktøren ringede vi til Animal
konstruktøren og passerede to felter. Vi havde kun ét felt at initialisere eksplicit: tail , som ikke er i Animal
. Husker vi, at vi nævnte, at den overordnede klassekonstruktør kaldes først, når et objekt oprettes? Derfor skal super() altid være først i en konstruktør! Ellers vil konstruktørlogikken blive overtrådt, og programmet vil generere en fejl.
public class Cat extends Animal {
String tail;
public Cat(String brain, String heart, String tail) {
this.tail = tail;
super(brain, heart);// Error!
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
Compileren ved, at når et objekt i en underklasse oprettes, kaldes basisklassekonstruktøren først. Og hvis du prøver at ændre denne adfærd manuelt, vil compileren ikke tillade det.
Hvordan et objekt skabes
Vi har tidligere set på et eksempel med en basis- og forældreklasse:Animal
og Cat
. Ved at bruge disse to klasser som eksempler, vil vi nu se på processen med at skabe et objekt og initialisere variabler. Vi ved, at der er statiske og instans (ikke-statiske) variabler . Vi ved også, at Animal
basisklassen har variable, og Cat
barneklassen har sine egne. For klarhedens skyld tilføjer vi én statisk variabel hver til klasserne Animal
og Cat
. AnimalCount - variablen i Animal
klassen vil repræsentere det samlede antal dyrearter på Jorden og catCountvariabel vil angive antallet af kattearter. Derudover vil vi tildele startværdier til alle ikke-statiske variable i begge klasser (som så vil blive ændret i konstruktøren).
public class Animal {
String brain = "Initial value of brain in the Animal class";
String heart = "Initial value of heart in the Animal class";
public static int animalCount = 7700000;
public Animal(String brain, String heart) {
System.out.println("Animal base class constructor is running");
System.out.println("Have the variables of the Animal class already been initialized?");
System.out.println("Current value of static variable animalCount = " + animalCount);
System.out.println("Current value of brain in the Animal class = " + this.brain);
System.out.println("Current value of heart in the Animal class = " + this.heart);
System.out.println("Have the variables of the Cat class already been initialized?");
System.out.println("Current value of static variable catCount = " + Cat.catCount);
this.brain = brain;
this.heart = heart;
System.out.println("Animal base class constructor is done!");
System.out.println("Current value of brain = " + this.brain);
System.out.println("Current value of heart = " + this.heart);
}
}
public class Cat extends Animal {
String tail = "Initial value of tail in the Cat class";
static int catCount = 37;
public Cat(String brain, String heart, String tail) {
super(brain, heart);
System.out.println("The cat class constructor has started (The Animal constructor already finished)");
System.out.println("Current value of static variable catCount = " + catCount);
System.out.println("Current value of tail = " + this.tail);
this.tail = tail;
System.out.println("Current value of tail = " + this.tail);
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
Så vi opretter en ny forekomst af Cat
klassen, som arver Animal
. Vi har tilføjet nogle detaljerede konsoloutput for at se, hvad der sker, og i hvilken rækkefølge. Dette er, hvad der vil blive vist, når et Cat
objekt oprettes: Animal base class constructor kører Er variablerne i Animal klassen allerede blevet initialiseret? Aktuel værdi af statisk variabel animalCount = 7700000 Aktuel værdi af hjerne i dyreklassen = Startværdi af hjerne i dyreklassen Nuværende værdi af hjerte i dyreklassen = Startværdi af hjerte i dyreklassen Har variablerne for Cat-klassen allerede blevet initialiseret? Aktuel værdi af statisk variabel catCount = 37 Dyrebaseklassekonstruktør er færdig! Aktuel værdi af hjerne = Hjerne Aktuel værdi hjerte = Hjerte Katteklassekonstruktøren er startet (Dyrekonstruktøren er allerede færdig) Aktuel værdi af statisk variabel catCount = 37 Aktuel værdi af hale = Startværdi af hale i Cat-klassen Aktuel værdi af hale = Hale Så nu kan vi tydeligt se rækkefølgen af variabel initialisering og konstruktørkald, når et nyt objekt oprettes:
- Statiske variable for basisklassen (
Animal
) initialiseres. I vores tilfælde erAnimal
klassens variable animalCount sat til 7700000. -
Statiske variabler for den underordnede klasse (
Cat
) initialiseres.Bemærk: vi er stadig inde i konstruktøren
Animal
, og vi har allerede vist:Animal base class constructor kører
Er variablerne i Animal klassen allerede blevet initialiseret?
Aktuel værdi af statisk variabel animalCount = 7700000
Aktuel værdi af hjerne i dyreklassen = Startværdi af hjerne i dyreklassen
Nuværende værdi af hjerte i dyreklassen = Startværdi af hjerte i dyreklassen
Har variablerne fra Cat-klassen allerede blevet initialiseret?
Aktuel værdi af statisk variabel catCount = 37 -
Derefter initialiseres de ikke-statiske variable i basisklassen . Vi har specifikt tildelt dem startværdier, som derefter erstattes i konstruktøren. Dyrekonstruktøren er ikke færdig endnu, men startværdierne for hjerne og hjerte er allerede blevet tildelt:
Animal base class constructor kører
Er variablerne i Animal klassen allerede blevet initialiseret?
Aktuel værdi af statisk variabel animalCount = 7700000
Aktuel værdi af hjerne i dyreklassen = Startværdi af hjerne i dyreklassen
Nuværende værdi af hjerte i dyreklassen = Startværdi af hjerte i dyreklassen -
Basisklassekonstruktøren starter.
Vi har allerede overbevist os selv om, at dette trin er fjerde: i de første tre trin i begyndelsen af konstruktørenAnimal
er mange variable allerede blevet tildelt værdier. -
Ikke-statiske felter i den underordnede klasse (
Cat
) initialiseres.
Dette sker førCat
konstruktøren begynder at køre.
Når den begynder at køre, har halevariablen allerede en værdi:Katteklassekonstruktøren er startet (Dyrekonstruktøren er allerede færdig) Aktuel værdi af statisk variabel catCount = 37 Aktuel værdi af hale = Startværdi af hale i Cat-klassen
-
Konstruktøren af
Cat
børneklassen kaldesOg sådan ser det ud at skabe et objekt i Java!
Jeg må sige, at vi ikke er store fans af udenadslære, men det er bedst at huske rækkefølgen af variabel initialisering og konstruktørkald .
Dette vil i høj grad øge din forståelse af programmets flow og tilstanden af dine objekter på ethvert bestemt tidspunkt.
Desuden bruger mange klasser ikke arv. I dette tilfælde gælder trinene relateret til basisklassen ikke.
Mere læsning: |
---|