Animal
فئة:
public class Animal {
String name;
int age;
}
يمكننا أن نعلن عن فئتين فرعيتين: Cat
و Dog
. ويتم ذلك باستخدام الكلمة الأساسية يمتد .
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 executed");
}
}
public class Cat extends Animal {
public Cat() {
System.out.println("Cat constructor executed!");
}
public static void main(String[] args) {
Cat cat = new Cat();
}
}
إخراج وحدة التحكم: تم تنفيذ مُنشئ الحيوان تم تنفيذ مُنشئ Cat! في الواقع، إنه يعمل بهذه الطريقة! لماذا؟ أحد الأسباب هو تجنب تكرار الحقول المشتركة بين الفئتين. على سبيل المثال، كل حيوان لديه قلب وعقل، ولكن ليس كل حيوان لديه ذيل. يمكننا أن نعلن عن حقول الدماغ والقلب ، وهي مشتركة بين جميع الحيوانات، في الفئة الأم، وحقل الذيل في الفئة الفرعية. . سنعلن الآن عن مُنشئ فئة يأخذ الوسائط لجميع الحقول الثلاثة. Animal
Cat
Cat
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
لا يحتوي على حقول دماغ وقلب . هذه الحقول "موروثة" من Animal
الفئة الأساسية. تتمتع الفئة الموروثة بإمكانية الوصول إلى حقول الفئة الأساسية ، بحيث تكون مرئية في Cat
فصلنا. ونتيجة لذلك، لا نحتاج إلى تكرار هذه الحقول في الفصل Cat
الدراسي. يمكننا أن نأخذهم من Animal
الفصل. علاوة على ذلك، يمكننا استدعاء مُنشئ الفئة الأساسية بشكل صريح في مُنشئ الفئة الفرعية. تسمى الفئة الأساسية أيضًا " الطبقة الفائقة ". لهذا السبب تستخدم Java الكلمة الأساسية 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
و Cat
. باستخدام هاتين الفئتين كأمثلة، سننظر الآن إلى عملية إنشاء كائن وتهيئة المتغيرات. نحن نعلم أن هناك متغيرات ثابتة ومتغيرات مثيلة (غير ثابتة) . نحن نعلم أيضًا أن Animal
الفئة الأساسية لها متغيرات، والفئة Cat
الفرعية لها متغيرات خاصة بها. للتوضيح، سنضيف متغيرًا ثابتًا واحدًا لكل فئة Animal
و Cat
. سيمثل المتغير AnimalCount في الفصل العدد الإجمالي لأنواع الحيوانات على الأرض، وسيشير المتغير catCount إلى عدد أنواع القطط. بالإضافة إلى ذلك، سنقوم بتعيين قيم البداية لجميع المتغيرات غير الثابتة في كلا الفئتين (والتي سيتم بعد ذلك تغييرها في المنشئ). Animal
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");
}
}
لذلك نحن نقوم بإنشاء مثيل جديد للفئة Cat
التي ترث Animal
. لقد أضفنا بعض مخرجات وحدة التحكم التفصيلية لمعرفة ما يحدث وبأي ترتيب. هذا ما سيتم عرضه عند Cat
إنشاء كائن: مُنشئ فئة الحيوان الأساسية قيد التشغيل هل تمت تهيئة متغيرات فئة الحيوان بالفعل؟ القيمة الحالية للمتغير الثابت AnimalCount = 7700000 القيمة الحالية للدماغ في فئة الحيوان = القيمة الأولية للدماغ في فئة الحيوان القيمة الحالية للقلب في فئة الحيوان = القيمة الأولية للقلب في فئة الحيوان هل لديك متغيرات فئة Cat بالفعل تمت التهيئة؟ القيمة الحالية للمتغير الثابت catCount = 37 تم الانتهاء من مُنشئ الفئة الأساسية للحيوان! القيمة الحالية للدماغ = الدماغ القيمة الحالية للقلب = القلب بدأ مُنشئ فئة القط (انتهى مُنشئ الحيوان بالفعل) القيمة الحالية للمتغير الثابت catCount = 37 القيمة الحالية للذيل = القيمة الأولية للذيل في فئة Cat القيمة الحالية للذيل = إذن ، يمكننا الآن أن نرى بوضوح ترتيب تهيئة المتغير واستدعاءات المنشئ عند إنشاء كائن جديد:
- تتم تهيئة المتغيرات الثابتة للفئة الأساسية ( ).
Animal
في حالتنا، تم تعيين AnimalCountAnimal
المتغير للفئة على 7700000. -
تتم تهيئة المتغيرات الثابتة للفئة الفرعية ( ).
Cat
ملاحظة: ما زلنا داخل
Animal
المُنشئ وقد عرضنا بالفعل:مُنشئ فئة الحيوان الأساسية قيد التشغيل
هل تمت تهيئة متغيرات فئة الحيوان بالفعل؟
القيمة الحالية للمتغير الثابت AnimalCount = 7700000
القيمة الحالية للدماغ في فئة الحيوان = القيمة الأولية للدماغ في فئة الحيوان
القيمة الحالية للقلب في فئة الحيوان = القيمة الأولية للقلب في فئة الحيوان
هل لديك متغيرات فئة Cat بالفعل تمت التهيئة؟
القيمة الحالية للمتغير الثابت catCount = 37 -
ثم تتم تهيئة المتغيرات غير الثابتة للفئة الأساسية . لقد قمنا بتعيين قيم أولية لهم على وجه التحديد، والتي يتم استبدالها بعد ذلك في المنشئ. لم ينته مُنشئ الحيوان بعد، ولكن تم بالفعل تعيين القيم الأولية للدماغ والقلب:
مُنشئ فئة الحيوان الأساسية قيد التشغيل
هل تمت تهيئة متغيرات فئة الحيوان بالفعل؟
القيمة الحالية للمتغير الثابت AnimalCount = 7700000
القيمة الحالية للدماغ في فئة الحيوان = القيمة الأولية للدماغ في فئة الحيوان
القيمة الحالية للقلب في فئة الحيوان = القيمة الأولية للقلب في فئة الحيوان -
يبدأ مُنشئ الفئة الأساسية .
لقد أقنعنا أنفسنا بالفعل أن هذه الخطوة هي الرابعة: في الخطوات الثلاث الأولى في بداية المنشئAnimal
، تم بالفعل تعيين قيم للعديد من المتغيرات. -
تتم تهيئة الحقول غير الثابتة للفئة الفرعية ( ). يحدث هذا قبل بدء تشغيل المنشئ. عندما يبدأ التشغيل، يكون للمتغير tail قيمة بالفعل:
Cat
Cat
بدأ مُنشئ فئة القط (انتهى مُنشئ الحيوان بالفعل) القيمة الحالية للمتغير الثابت catCount = 37 القيمة الحالية للذيل = القيمة الأولية للذيل في فئة Cat
-
Cat
يتم استدعاء منشئ فئة الطفلوهذا ما يبدو عليه إنشاء كائن في Java!
يجب أن أقول إننا لسنا من كبار المعجبين بالتعلم عن ظهر قلب، ولكن من الأفضل حفظ ترتيب التهيئة المتغيرة واستدعاءات المنشئ .
سيؤدي هذا إلى زيادة فهمك لتدفق البرنامج بشكل كبير، وحالة الكائنات الخاصة بك في أي لحظة معينة.
علاوة على ذلك، فإن العديد من الطبقات لا تستخدم الميراث. وفي هذه الحالة، لا تنطبق الخطوات المتعلقة بالفئة الأساسية.
المزيد من القراءة: |
---|
GO TO FULL VERSION