new
، وكل شيء جاهز :) هنا سنتحدث عما يحدث داخل الكمبيوتر وجهاز Java عندما نكتب، على سبيل المثال:
Cat cat = new Cat();
لقد تحدثنا عن هذا من قبل، ولكن فقط في حالة سنذكرك:
- أولا، يتم تخصيص الذاكرة لتخزين الكائن.
- بعد ذلك، تقوم آلة Java بإنشاء مرجع للكائن (في حالتنا، المرجع هو Cat cat).
- وأخيرا، تتم تهيئة المتغيرات ويتم استدعاء المنشئ (سننظر في هذه العملية بمزيد من التفصيل).
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++;
}
}
الفصل Truck
عبارة عن تطبيق لشاحنة تحتوي على حقول تمثل عامها وطرازها وسرعتها القصوى. الآن نريد إنشاء كائن واحد من هذا القبيل:
public class Main {
public static void main(String[] args) throws IOException {
Truck truck = new Truck(2017, "Scania S 500 4x2", 220);
}
}
بالنسبة لجهاز جافا، ستبدو العملية كما يلي:
-
أول ما يحدث هو تهيئة المتغيرات الثابتة للفئة
Vehicle
. نعم، قلت الطبقةVehicle
، وليسTruck
. تتم تهيئة المتغيرات الثابتة قبل استدعاء المنشئات، ويبدأ ذلك في الفئة الأصل. دعونا نحاول التحقق من ذلك. قمنا بتعيينvehicleCounter
الحقل فيVehicle
الفصل على 10 وحاول عرضه في كل منVehicle
المنشئينTruck
.public 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++; } }
لقد وضعنا عبارة println عمدًا في بداية المُنشئ
Truck
للتأكد من أن حقول الشاحنة لم تتم تهيئتها بعد عندvehicleCounter
عرضها.وهذه هي النتيجة:
10 10
-
بعد تهيئة المتغيرات الثابتة للفئة الأصلية، تتم تهيئة المتغيرات الثابتة للفئة الفرعية. في حالتنا، هذا هو
truckCounter
مجال الطبقةTruck
.لنقم بتجربة أخرى حيث سنحاول عرض قيمة
truckCounter
داخلTruck
المُنشئ قبل تهيئة الحقول الأخرى: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++; } }
كما ترون، تم بالفعل تعيين القيمة 10 للمتغير الثابت لدينا عندما
Truck
يبدأ المنشئ. -
لم يحن الوقت بعد للبناة! تستمر التهيئة المتغيرة. تتم تهيئة المتغيرات غير الثابتة للفئة الأصلية ثالثًا. كما ترون، فإن الميراث يعقد بشكل كبير عملية إنشاء كائن، ولكن لا يوجد شيء يمكنك القيام به حيال ذلك: عليك فقط حفظ بعض الأشياء في البرمجة :)
كتجربة، يمكننا تعيين بعض القيمة الأولية للمتغير
description
فيVehicle
الفئة، ثم تغييرها في المنشئ.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; } }
لنقم بتشغيل
main()
طريقتنا لإنشاء شاحنة:public class Main { public static void main(String[] args) throws IOException { Truck truck = new Truck(2017, "Scania S 500 4x2", 220); } }
نحصل على النتيجة التالية:
Initial value of the description field Vehicle
وهذا يثبت أنه عندما
Vehicle
يبدأ المنشئ،description
تم بالفعل تعيين قيمة للحقل. -
أخيرا، حان الوقت للبناة! بتعبير أدق، حان الوقت لمنشئ الطبقة الأساسية. يتم استدعاؤه في الخطوة الرابعة من عملية إنشاء الكائن.
وهذا أيضًا سهل التحقق إلى حد ما. دعونا نحاول إخراج سطرين إلى وحدة التحكم: أحدهما داخل
Vehicle
مُنشئ الفئة الأساسية، والثاني داخلTruck
المُنشئ. يجب أن نقتنع بأن السطر الموجود بالداخلVehicle
يظهر أولاً: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++; }
سنقوم بتشغيل طريقتنا
main()
وننظر إلى النتيجة:Hello from the Vehicle constructor! Hello from the Truck constructor!
ممتاز. وهذا يعني أننا لسنا مخطئين :) دعونا نمضي قدما.
-
حان الوقت الآن لتهيئة الحقول غير الثابتة للفصل الفرعي، أي فصلنا
Truck
. لا تتم تهيئة الحقول الموجودة مباشرة داخل الفصل الذي يتم إنشاء مثيل له حتى الخطوة الخامسة! مفاجئ، ولكنه حقيقي :) مرة أخرى، سنجري فحصًا بسيطًا - تمامًا كما هو الحال مع الفئة الأصلية: سنضع بعض القيمة الأولية للمتغيرmaxSpeed
وفيTruck
المنشئ سنتحقق من أنه تم تعيين القيمة قبل بدء المنشئ: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++; } }
إخراج وحدة التحكم:
Initial value of maxSpeed = 150
كما ترون، عندما
Truck
يبدأ المنشئ،maxSpeed
يساوي بالفعل 150! -
Truck
يتم استدعاء منشئ فئة الطفل.وفقط عند هذه النقطة، أخيرًا، سيتم استدعاء منشئ الفئة التي نقوم بإنشاء مثيل لها!
فقط في الخطوة السادسة سيتم تخصيص القيم التي نمررها إلى شاحنتنا للحقول.
كما ترون، "إنشاء" شاحنة، أي عملية إنشاء الكائن، ليس بالأمر السهل. ولكن يبدو أننا قمنا بتقسيمها إلى أجزاء أصغر :)
GO TO FULL VERSION