Animal
(حیوان) داریم:
public class Animal {
String name;
int age;
}
ما می توانیم برای آن، به عنوان مثال، 2 کلاس descendant ایجاد کنیم - Cat
و Dog
. این کار با استفاده از کلمه کلیدی انجام می شود extends
.
public class Cat extends Animal {
}
public class Dog extends Animal {
}
این ممکن است در آینده برای ما مفید باشد. به عنوان مثال، اگر وظیفه گرفتن موش باشد، یک شی در برنامه ایجاد می کنیم Cat
. اگر وظیفه دویدن به دنبال چوب است، از شی استفاده می کنیم Dog
. و اگر برنامه ای ایجاد کنیم که یک کلینیک دامپزشکی را شبیه سازی کند، با کلاس کار می کند Animal
(تا بتواند هم گربه ها و هم سگ ها را درمان کند). یادآوری این نکته برای آینده بسیار مهم است که هنگام ایجاد یک شی، ابتدا سازنده کلاس پایه آن فراخوانی می شود و تنها پس از آن سازنده خود کلاس که شیء آن را ایجاد می کنیم فراخوانی می شود. یعنی هنگام ایجاد یک شی، Cat
سازنده کلاس ابتدا کار می کند Animal
و تنها پس از آن سازنده Cat
. برای اطمینان از این موضوع، بیایید به سازنده ها Cat
و Animal
خروجی ها به کنسول اضافه کنیم.
public class Animal {
public Animal() {
System.out.println("Animal constructor completed");
}
}
public class Cat extends Animal {
public Cat() {
System.out.println("The constructor Cat worked!");
}
public static void main(String[] args) {
Cat cat = new Cat();
}
}
خروجی کنسول:
Отработал конструктор Animal
Отработал конструктор Cat!
در واقع، همه چیز اینگونه است! این برای چیست؟ به عنوان مثال، برای جلوگیری از تکرار فیلدهای مشترک دو کلاس. مثلاً هر حیوانی قلب و مغز دارد اما هر حیوانی دم ندارد. ما می توانیم فیلدهای مشترک برای همه حیوانات brain
در heart
کلاس والد Animal
و یک فیلد tail
در زیر کلاس اعلام کنیم Cat
. اکنون یک سازنده برای کلاس ایجاد می کنیم Cat
که در آن هر 3 فیلد را پاس می کنیم.
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");
}
}
توجه کنید:سازنده با موفقیت کار می کند، اگرچه کلاس Cat
دارای فیلدها brain
و heart
. این فیلدها از کلاس پایه "کشیده شدند" Animal
. کلاس descendant به فیلدهای کلاس پایه دسترسی دارد، بنابراین Cat
آنها در کلاس ما قابل مشاهده هستند. Cat
بنابراین، ما نیازی به کپی کردن این فیلدها در کلاس نداریم - می توانیم آنها را از کلاس بگیریم Animal
. علاوه بر این، میتوانیم به صراحت سازنده کلاس پایه را در سازنده کلاس decendant فراخوانی کنیم. کلاس پایه نیز " superclass " نامیده می شود، به همین دلیل جاوا از کلمه کلیدی استفاده می کند super
. در مثال قبلی
public Cat(String brain, String heart, String tail) {
this.brain = brain;
this.heart = heart;
this.tail = tail;
}
ما به طور جداگانه هر فیلد را که در کلاس والد ما قرار دارد اختصاص دادیم. در واقع، شما مجبور نیستید این کار را انجام دهید. کافی است سازنده کلاس والد را فراخوانی کرده و پارامترهای لازم را به آن ارسال کنید:
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");
}
}
در سازنده، Cat
سازنده را فراخوانی کردیم Animal
و دو فیلد را به آن پاس دادیم. ما فقط باید به صراحت یک فیلد را مقداردهی کنیم - tail
که Animal
وجود ندارد. به یاد دارید که چگونه گفتیم وقتی یک شی ایجاد می شود، سازنده کلاس والد ابتدا فراخوانی می شود؟ بنابراین، به همین دلیل است که کلمه super()
همیشه باید اول در سازنده باشد! در غیر این صورت، منطق سازنده ها خراب می شود و برنامه خطا ایجاد می کند.
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");
}
}
کامپایلر می داند که هنگام ایجاد یک شی از یک کلاس نزول، سازنده کلاس پایه ابتدا فراخوانی می شود. و اگر سعی کنید به صورت دستی این رفتار را تغییر دهید، اجازه نمی دهد.
فرآیند ایجاد یک شی.
در بالا به مثالی با کلاس پایه و والد نگاه کردیم -Animal
and Cat
. اکنون با استفاده از این دو کلاس به عنوان مثال، به روند ایجاد یک شی و مقداردهی اولیه متغیرها خواهیم پرداخت. می دانیم که متغیرها ثابت و متغیرهای نمونه (غیر ایستا) هستند. همچنین می دانیم که کلاس پایه Animal
متغیرهای خاص خود را دارد و کلاس decendant نیز متغیرهای Cat
خود را دارد. Animal
بیایید برای وضوح Cat
یک متغیر استاتیک به کلاس اضافه کنیم . متغیر animalCount
کلاس Animal
تعداد کل گونه های جانوری روی زمین و متغیر catsCount
تعداد گونه های گربه خواهد بود. علاوه بر این، مقادیر شروع را به همه متغیرهای غیر استاتیک هر دو کلاس اختصاص می دهیم (که سپس در سازنده تغییر می کند).
public class Animal {
String brain = "The initial value of brain in the Animal class";
String heart = "The initial value of heart in the Animal class";
public static int animalCount = 7700000;
public Animal(String brain, String heart) {
System.out.println("The constructor of the Animal base class is being executed");
System.out.println("Have the variables of the Animal class already been initialized?");
System.out.println("The current value of the static variable animalCount = " + animalCount);
System.out.println("Current value of brain in class Animal = " + this.brain);
System.out.println("Current value of heart in class Animal = " + this.heart);
System.out.println("Have the variables of the Cat class already been initialized?");
System.out.println("The current value of the static variable catsCount = " + Cat.catsCount);
this.brain = brain;
this.heart = heart;
System.out.println("Animal base class constructor completed!");
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 = "The initial value of tail in the Cat class";
static int catsCount = 37;
public Cat(String brain, String heart, String tail) {
super(brain, heart);
System.out.println("The constructor of the Cat class has started (the Animal constructor has already been executed)");
System.out.println("The current value of the static variable catsCount = " + catsCount);
System.out.println("Current value tail = " + this.tail);
this.tail = tail;
System.out.println("Current value tail = " + this.tail);
}
public static void main(String[] args) {
Cat cat = new Cat("Brain", "Heart", "Tail");
}
}
بنابراین، یک شی جدید از کلاس Cat
به ارث برده شده از Animal
. بیایید خروجی دقیق کنسول را به برنامه خود اضافه کنیم تا ببینیم چه اتفاقی خواهد افتاد و به چه ترتیبی. این چیزی است که در نتیجه ایجاد یک شی به کنسول خروجی می شود Cat
:
Выполняется конструктор базового класса Animal
Были ли уже проинициализированы переменные класса Animal?
Текущее meaning статической переменной animalCount = 7700000
Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal
Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
Были ли уже проинициализированы переменные класса Cat?
Текущее meaning статической переменной catsCount = 37
Конструктор базового класса Animal завершил работу!
Текущее meaning brain = Мозг
Текущее meaning heart = Сердце
Конструктор класса Cat начал работу (конструктор Animal уже был выполнен)
Текущее meaning статической переменной catsCount = 37
Текущее meaning tail = Изначальное meaning tail в классе Cat
Текущее meaning tail = Хвост
بنابراین، اکنون می توانیم به وضوح ببینیم که متغیرها به چه ترتیبی مقداردهی اولیه می شوند و سازنده ها هنگام ایجاد یک شی جدید فراخوانی می شوند:
-
متغیرهای استاتیک کلاس پایه ( ) مقداردهی اولیه می شوند
Animal
. در مورد ما، به متغیرanimalCount
کلاسAnimal
مقدار 7700000 اختصاص داده می شود. -
متغیرهای استاتیک کلاس نزول ( ) مقداردهی اولیه می شوند
Cat
. توجه کنید - ما هنوز داخل سازنده هستیمAnimal
و کنسول قبلاً می گوید:Выполняется конструктор базового класса Animal Были ли уже проинициализированы переменные класса Animal? Текущее meaning статической переменной animalCount = 7700000 Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal Были ли уже проинициализированы переменные класса Cat? Текущее meaning статической переменной catsCount = 37
-
سپس، متغیرهای غیراستاتیک کلاس پایه مقداردهی اولیه می شوند . ما به طور خاص مقادیر اولیه را به آنها اختصاص دادیم، که سپس به مقادیر جدید در سازنده تغییر می کنند. سازنده
Animal
هنوز کار خود را کامل نکرده است، اما مقادیر اولیه قبلاً اختصاص داده شدهbrain
استheart
:Выполняется конструктор базового класса Animal Были ли уже проинициализированы переменные класса Animal? Текущее meaning статической переменной animalCount = 7700000 Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
-
سازنده کلاس پایه شروع به کار می کند .
قبلاً دیدیم که این مرحله تنها مرحله چهارم است: در سه نقطه اول، در زمانی که سازنده شروع به کار می کند،
Animal
به بسیاری از متغیرها قبلاً مقادیر اختصاص داده شده است. -
راه اندازی فیلدهای غیر استاتیک یک کلاس فرزند (
Cat
).Cat
قبل از شروع کار طراح اتفاق می افتد .در زمانی که او شروع به کار کرد، متغیر
tail
قبلاً یک مقدار داشت:Конструктор класса Cat начал работу (конструктор Animal уже был выполнен) Текущее meaning статической переменной catsCount = 37 Текущее meaning tail = Изначальное meaning tail в классе Cat
-
سازنده کلاس decendant نامیده می شود
Cat
GO TO FULL VERSION