

Animal
klass:
public class Animal {
String name;
int age;
}
Vi kan deklarera 2 barnklasser: Cat
och Dog
. Detta görs med nyckelordet extends .
public class Cat extends Animal {
}
public class Dog extends Animal {
}
Vi kan ha nytta av detta i framtiden. Till exempel, om det finns en uppgift att fånga möss, skapar vi ett Cat
objekt i vårt program. Om uppgiften är att jaga efter en pinne, så använder vi ett Dog
föremål. Och om vi skapar ett program som simulerar en veterinärklinik kommer det att fungera med klassen ( Animal
och därmed kunna behandla både katter och hundar). Det är mycket viktigt att komma ihåg att när ett objekt skapas, kallas konstruktorn för dess basklass först . Först efter att konstruktören är klar kör programmet konstruktorn för klassen som motsvarar objektet vi skapar. Med andra ord, när du skapar ett Cat
objekt körs konstruktorn först ,Animal
och först efteråt körsCat
konstruktör utförd . För att se detta, lägg till lite konsolutdata till Cat
och Animal
konstruktörerna.
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();
}
}
Konsolutdata: Djurkonstruktör körd Cat konstruktor körd! Visst, det fungerar så! Varför? Ett skäl är att undvika att duplicera fält som delas mellan de två klasserna. Till exempel har varje djur ett hjärta och en hjärna, men inte alla djur har en svans. Vi skulle kunna deklarera hjärn- och hjärtfält , som är gemensamma för alla djur, i Animal
föräldraklassen, och ett svansfält i Cat
underklassen. . Nu ska vi deklarera en Cat
klasskonstruktor som tar argument för alla tre fälten.
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");
}
}
Notera: Konstruktorn fungerar korrekt även om klassen Cat
inte har några hjärn- och hjärtfält . Dessa fält "ärvs" från Animal
basklassen. Den ärvda klassen har tillgång till fälten i basklassen , så de är synliga i vår Cat
klass. Som ett resultat behöver vi inte duplicera dessa fält i klassen Cat
. Vi kan ta dem från Animal
klassen. Dessutom kan vi uttryckligen kalla basklasskonstruktorn i barnklasskonstruktorn. En basklass kallas också en " superklass ". Det är därför Java använder nyckelordet super för att indikera basklassen. I föregående exempel
public Cat(String brain, String heart, String tail) {
this.brain = brain;
this.heart = heart;
this.tail = tail;
}
Vi tilldelade varje fält separat i vår föräldraklass. Vi behöver faktiskt inte göra det här. Det räcker att anropa den överordnade klasskonstruktören och skicka de nödvändiga argumenten:
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
konstruktorn ringde vi Animal
konstruktören och passerade två fält. Vi hade bara ett fält att explicit initiera: tail , som inte är i Animal
. Kom ihåg att vi nämnde att den överordnade klasskonstruktorn anropas först när ett objekt skapas? Det är därför super() alltid ska vara först i en konstruktor! Annars kommer konstruktorlogiken att kränkas och programmet genererar ett fel.
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");
}
}
Kompilatorn vet att när ett objekt i en barnklass skapas, anropas basklasskonstruktorn först. Och om du försöker ändra detta beteende manuellt, tillåter inte kompilatorn det.
Hur ett objekt skapas
Vi har tidigare tittat på ett exempel med en bas- och förälderklass:Animal
och Cat
. Med dessa två klasser som exempel kommer vi nu att titta på processen att skapa ett objekt och initiera variabler. Vi vet att det finns statiska och instansvariabler (icke-statiska) . Vi vet också att Animal
basklassen har variabler och att Cat
barnklassen har sina egna. För tydlighetens skull lägger vi till en statisk variabel var och en till klasserna Animal
och . Cat
AnimalCount - variabeln i Animal
klassen kommer att representera det totala antalet djurarter på jorden och catCountvariabel kommer att beteckna antalet kattarter. Dessutom kommer vi att tilldela startvärden till alla icke-statiska variabler i båda klasserna (som sedan kommer att ändras i konstruktorn).
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 skapar en ny instans av Cat
klassen, som ärver Animal
. Vi har lagt till lite detaljerad konsolutgång för att se vad som händer och i vilken ordning. Detta är vad som kommer att visas när ett Cat
objekt skapas: Djurbasklasskonstruktorn körs Har variablerna för klassen Animal redan initierats? Aktuellt värde för statisk variabel animalCount = 7700000 Aktuellt värde för hjärnan i klassen Animal = Initialt värde på hjärnan i klassen Animal Aktuellt värde på hjärta i klassen Animal = Initialt värde på hjärta i klassen Animal Har variablerna för klassen Cat redan har initierats? Aktuellt värde för statisk variabel catCount = 37 Djurbasklasskonstruktör är klar! Aktuellt värde för hjärna = Hjärna Aktuellt värde hjärta = Hjärta Kattklasskonstruktören har startat (Djurkonstruktören är redan klar) Aktuellt värde för statisk variabel catCount = 37 Aktuellt värde för svans = Initialt värde för svans i Katt-klassen Aktuellt värde på svans = Svans Så nu kan vi tydligt se ordningen för variabelinitiering och konstruktoranrop när ett nytt objekt skapas:
- Statiska variabler för basklassen (
Animal
) initieras. I vårt fall ärAnimal
klassens variabel animalCount satt till 7700000. -
Statiska variabler för den underordnade klassen (
Cat
) initieras.Obs: vi är fortfarande inne i
Animal
konstruktören och vi har redan visat:Djurbasklasskonstruktorn körs
Har variablerna för klassen Animal redan initierats?
Aktuellt värde för statisk variabel animalCount = 7700000
Aktuellt värde för hjärnan i klassen Animal = Initialt värde för hjärnan i klassen Animal
Nuvarande värde på hjärta i klassen Animal = Initialt värde på hjärta i klassen
Animal har initierats?
Aktuellt värde för statisk variabel catCount = 37 -
Sedan initieras de icke-statiska variablerna för basklassen . Vi tilldelade dem specifikt initiala värden, som sedan ersätts i konstruktorn. Djurkonstruktören har inte avslutats än, men de initiala värdena för hjärna och hjärta har redan tilldelats:
Djurbasklasskonstruktorn körs
Har variablerna för klassen Animal redan initierats?
Aktuellt värde för statisk variabel animalCount = 7700000
Aktuellt värde för hjärnan i klassen Animal =
Initialt värde på hjärnan i klassen Djur. -
Basklasskonstruktorn startar.
Vi har redan övertygat oss själva om att detta steg är fjärde: i de första tre stegen i början av konstruktornAnimal
har många variabler redan tilldelats värden. -
Icke-statiska fält för den underordnade klassen ( ) initieras
Cat
.
Detta händer innanCat
konstruktorn börjar köra.
När den börjar köras har svansvariabeln redan ett värde:Kattklasskonstruktören har startat (Djurkonstruktören är redan klar) Aktuellt värde för statisk variabel catCount = 37 Aktuellt värde på svans = Initialt värde för svans i klassen Cat
-
Konstruktören av
Cat
barnklassen kallasOch så ser det ut att skapa ett objekt i Java!
Jag måste säga att vi inte är stora fans av rote-learning, men det är bäst att memorera ordningen för variabelinitiering och konstruktoranrop .
Detta kommer att avsevärt öka din förståelse för programmets flöde och tillståndet för dina objekt vid varje särskilt ögonblick.
Dessutom använder många klasser inte arv. I det här fallet gäller inte stegen relaterade till basklassen.
Mer läsning: |
---|
GO TO FULL VERSION