المنشئ Constructor في Java
لماذا نحتاج Constructor؟ وكيف يهيّئ الكائن تلقائياً عند إنشائه؟ وما الفرق بينه وبين الدوال العادية؟ مع أمثلة عملية مفصّلة.
المشكلة — لماذا نحتاج Constructor؟
في الدرس السابق أنشأنا كائناً ثم بدأنا نضع القيم يدوياً — سطراً سطراً:
Person p1 = new Person(); p1.name = "Ahmed"; p1.age = 25; p1.email = "ahmed@example.com"; p1.city = "Riyadh"; p1.salary = 5000; // 5 أسطر فقط لإنشاء شخص واحد — وقد ننسى خاصية!
هذا صحيح، لكنه يصبح مرهقاً مع كثرة الخصائص. هنا يأتي دور المنشئ (Constructor) — يهيّئ الكائن بكل قيمه دفعة واحدة عند إنشائه.
بدون Constructor
سطر لكل خاصية — يمكن نسيان تعبئة خاصية مهمة
مع Constructor
سطر واحد — الكائن جاهز بكل بياناته فوراً
ما هو Constructor وكيف نتعرّف عليه؟
المنشئ يشبه الدالة لكنه خاص جداً — يعمل تلقائياً في اللحظة التي تكتب فيها new Person(...).
الفرق بين Constructor والدالة العادية:
| الميزة | Constructor | دالة عادية |
|---|---|---|
| الاسم | نفس اسم الكلاس تماماً | أي اسم تختاره |
| نوع الإرجاع | لا يوجد (لا void ولا int) | void أو int أو String... |
| وقت التشغيل | تلقائياً عند new | عند استدعائها يدوياً |
| الهدف | تهيئة الكائن فقط | أي غرض تريده |
تشبيه: Constructor مثل استمارة التسجيل التي تملأها عند التسجيل في موقع — تُملأ مرة واحدة وتكون بياناتك جاهزة فوراً.
كيف نكتب Constructor؟
سننشئ Constructor للكلاس Person يستقبل الاسم والعمر عند إنشاء الكائن مباشرةً:
class Person { // الخصائص String name; int age; // ← المنشئ Constructor Person(String n, int a) { name = n; ← خزّن n في name age = a; ← خزّن a في age } }
Person
اسم Constructor = اسم الكلاس
لاحظ أن اسم المنشئ هو Person — نفس اسم الكلاس بالضبط، وهذا إلزامي.
String n
المدخلات (Parameters)
نستقبل قيمتين: n للاسم و a للعمر. سنمررهما عند الإنشاء.
name = n
تعيين القيم للخصائص
نأخذ القيمة الواردة n ونخزّنها في خاصية الكائن name.
كيف نستخدم Constructor عند إنشاء الكائن؟
الآن بدل 3 أسطر منفصلة، يمكننا إنشاء الشخص بسطر واحد:
❌ قبل Constructor
Person p1 = new Person(); p1.name = "Ahmed"; p1.age = 25; // 3 أسطر
✅ مع Constructor
Person p1 = new Person("Ahmed", 25); // سطر واحد فقط! ✨
// إنشاء كائنات بسطر واحد لكل منها Person p1 = new Person("Ahmed", 25); Person p2 = new Person("Sara", 20); Person p3 = new Person("Ali", 30); System.out.println(p1.name + " - " + p1.age); System.out.println(p2.name + " - " + p2.age);
Ahmed - 25 Sara - 20
🔍 ماذا يحدث خطوة بخطوة عند كتابة new Person("Ahmed", 25)؟
"Ahmed" إلى المعامل n و 25 إلى المعامل a
name = n و age = a فيُخزّن الاسم والعمر
p1 جاهز للاستخدام فوراً بكل بياناته
الكلمة المحجوزة this — أفضل طريقة للكتابة
في المثال السابق استخدمنا أسماء مختلفة للمعاملات (n و a) لتجنب التشابه مع الخصائص. لكن المبرمجون المحترفون يستخدمون نفس الأسماء مع الكلمة المحجوزة this.
this تعني "هذا الكائن الحالي" — تُستخدم للتمييز بين خاصية الكائن والمعامل اللي له نفس الاسم.
بدون this (أسماء مختلفة)
Person(String n, int a) { name = n; age = a; }
مع this (نفس الأسماء — أوضح)
Person(String name, int age) { this.name = name; this.age = age; }
ما معنى this.name = name؟
this.name
= خاصية الكائن الحالي المسماة name
name
= المعامل (Argument) الوارد للConstructor
name وخزّنها في خاصية name الخاصة بهذا الكائن.
لماذا Constructor مهم؟ — الفوائد
كود أقصر وأوضح
بدل 4 أسطر لكل كائن، تصبح سطراً واحداً. مع 10 كائنات، الفرق يصبح واضحاً جداً.
يُجبر على تعبئة البيانات الأساسية
إذا كان Constructor يطلب name و age — لا يمكنك إنشاء كائن بدون تمريرهما. هذا يمنع نسيان خاصية مهمة.
الكائن جاهز للاستخدام فوراً
بعد سطر الإنشاء مباشرةً، يمكنك استخدام p1.name و p1.age بثقة — لا تحتاج تتحقق هل تم تعبئتها أم لا.
📌 ملاحظة متقدمة
يمكن أن يوجد أكثر من Constructor في نفس الكلاس بمدخلات مختلفة — هذا يُسمى Constructor Overloading. مثلاً constructor بدون مدخلات وآخر بمدخلين. سنتعلم هذا في المستويات القادمة.
أخطاء شائعة عند المبتدئين ⚠️
كتابة نوع إرجاع للConstructor
❌ خطأ
void Person(String name) {
أصبح دالة عادية وليس Constructor!
✅ صحيح
Person(String name) {
بدون void أو أي نوع إرجاع
اسم Constructor لا يطابق اسم الكلاس
❌ خطأ
class Person {
person(String n) { }
person بحرف صغير ≠ Person
✅ صحيح
class Person {
Person(String n) { }
تمرير عدد قيم مختلف عن المطلوب
❌ خطأ
Person(String n, int a) {...}
new Person("Ahmed");
Constructor يطلب 2 قيم — أعطيته 1
✅ صحيح
Person(String n, int a) {...}
new Person("Ahmed", 25);
📋 ملخص الدرس
Constructor يهيّئ الكائن تلقائياً عند new
اسمه = اسم الكلاس — بدون نوع إرجاع
this.name للتمييز بين خاصية الكائن والمعامل
يجبر على تعبئة البيانات الأساسية منذ البداية
⏭️ في الدرس القادم:
سنتعلم Encapsulation (التغليف) — كيف نحمي بيانات الكائن بحيث لا يعبث بها أي جزء من البرنامج بشكل مباشر، باستخدام private و getter/setter.