أساسيات البرمجة الكائنيّة

المُنشِئات والكلمة المفتاحية this

15 دقيقة الدرس 3 من 14

المُنشِئات والكلمة المفتاحية this

في الدرس السابق أضفت للفئة حقولًا وأساليب تصف الحالة والسلوك. لكن كيف يُولَد الكائن وهو يحمل بيانات ذات معنى منذ البداية؟ هذه هي مهمة المُنشِئ (Constructor). وحين تكون داخل المُنشِئ، كيف تُشير إلى الكائن الذي يُبنى في تلك اللحظة؟ هذه هي مهمة الكلمة المفتاحية this.

ما هو المُنشِئ؟

المُنشِئ هو أسلوب خاص تستدعيه Java تلقائيًا حين تكتب new ClassName(...). يشبه الأسلوب العادي لكنه لا يملك نوع إرجاع (ولا حتى void)، ويجب أن يتطابق اسمه تمامًا مع اسم الفئة بما فيه حالة الأحرف.

فكرة أساسية: المُنشِئ لا يُنشِئ الكائن — فالـ JVM تُخصّص الذاكرة أولًا. مهمة المُنشِئ هي تهيئة حقول الكائن المُخصَّص حديثًا قبل أن يتمكن أي طرف آخر من استخدامه.

المُنشِئ الافتراضي

إن لم تكتب أي مُنشِئ، تُولّد Java بصمت مُنشِئًا افتراضيًا (بلا وسيطات) نيابةً عنك. يُهيّئ هذا المُنشِئ كل حقل بقيمة الصفر المناسبة لنوعه: 0 للأعداد، وfalse للقيم المنطقية، وnull للمراجع.

public class BankAccount { String owner; double balance; // لا يوجد مُنشِئ — تُوفّر Java: // public BankAccount() { } } // الاستخدام BankAccount acct = new BankAccount(); System.out.println(acct.owner); // null System.out.println(acct.balance); // 0.0

هذا مقبول للنماذج الأولية السريعة، لكن معظم الفئات الحقيقية تحتاج أن تُضبط حقولها بقيم ذات معنى منذ لحظة الإنشاء.

يختفي المُنشِئ الافتراضي حالما تكتب أي مُنشِئ بنفسك. إن أضفت مُنشِئًا بوسيطات ولا تزال تريد مُنشِئًا بلا وسيطات، يجب كتابة كليهما صراحةً.

المُنشِئات ذات الوسيطات

يقبل المُنشِئ ذو الوسيطات مُدخلات كي يتمكن المستدعي من تحديد الحالة الابتدائية:

public class BankAccount { String owner; double balance; // مُنشِئ بوسيطات public BankAccount(String owner, double balance) { this.owner = owner; this.balance = balance; } } // الاستخدام BankAccount acct = new BankAccount("Alice", 1000.00); System.out.println(acct.owner); // Alice System.out.println(acct.balance); // 1000.0

الآن كل BankAccount مضمون أن يبدأ بصاحب محدد ورصيد صريح. سيرفض المُصرِّف استدعاء new BankAccount() بلا وسيطات، مما يمنع إنشاء حسابات بأصحاب قيمتهم null عن طريق الخطأ.

الكلمة المفتاحية this — فصل التسميات المتشابهة

في المثال أعلاه، تحمل وسيطة المُنشِئ الاسم owner وكذلك الحقل. داخل المُنشِئ، تُخفي الوسيطة المحلية الحقلَ بنفس الاسم. كتابة owner = owner ببساطة ستُسنِد الوسيطة إلى نفسها — عملية بلا أثر. تحل this هذا بأناقة:

  • this.owner — يُشير إلى الحقل في الكائن الحالي.
  • owner (بلا بادئة) — يُشير إلى الوسيطة المحلية.
public BankAccount(String owner, double balance) { this.owner = owner; // الحقل = الوسيطة this.balance = balance; // الحقل = الوسيطة }

this ببساطة مرجع للكائن الذي يُبنى حاليًا (أو الكائن الذي يُستدعى عليه الأسلوب). وهي متاحة في أي أسلوب أو مُنشِئ غير ثابت.

نصيحة تسمية: استخدام نفس الاسم للوسيطات والحقول (مع التمييز بـ this) هو الأسلوب الأكثر شيوعًا في Java. يجعل النية واضحة تمامًا: "أسنِد الوسيطة إلى الحقل المتطابق في الاسم."

تعدد المُنشِئات (Overloading)

تسمح Java بتعريف مُنشِئات متعددة طالما تختلف قوائم وسيطاتها (عددًا أو أنواعًا). يُسمى هذا تعدد المُنشِئات:

public class BankAccount { String owner; double balance; // المُنشِئ الأول — صاحب الحساب والرصيد الابتدائي public BankAccount(String owner, double balance) { this.owner = owner; this.balance = balance; } // المُنشِئ الثاني — صاحب الحساب فقط، الرصيد يبدأ بالصفر public BankAccount(String owner) { this.owner = owner; this.balance = 0.0; } } BankAccount savings = new BankAccount("Bob", 500.00); BankAccount checking = new BankAccount("Bob"); // balance = 0.0

تسلسل المُنشِئات بـ this()

تكرار منطق التهيئة عبر مُنشِئات متعددة أمر هشّ — إن تغيّر المنطق يجب تحديث كل نسخة. يحل تسلسل المُنشِئات هذه المشكلة: يستدعي مُنشِئ مُنشِئًا آخر في نفس الفئة باستخدام this(...).

public class BankAccount { String owner; double balance; String currency; // المُنشِئ "الأساسي" — كل الحقول تُضبط هنا public BankAccount(String owner, double balance, String currency) { this.owner = owner; this.balance = balance; this.currency = currency; } // مُنشِئ مختصر: العملة الافتراضية "USD" public BankAccount(String owner, double balance) { this(owner, balance, "USD"); // يستدعي المُنشِئ ذا الثلاث وسيطات } // مُنشِئ مختصر: رصيد صفر وعملة USD public BankAccount(String owner) { this(owner, 0.0); // يستدعي المُنشِئ ذا الوسيطتين، الذي يستدعي ذا الثلاث } }
قاعدة: يجب أن يكون استدعاء this(...) أول سطر داخل المُنشِئ دون استثناء. لا يمكن تنفيذ أي عمل آخر قبل التفويض. هذا يضمن اكتمال تهيئة الكائن قبل تشغيل أي منطق إضافي.

النمط المُعتاد — مُنشِئ واحد مكتمل الوصف يؤدي كل العمل، ومُنشِئات أقصر تُفوّض إليه — يُبقي منطق التهيئة في مكان واحد ويُسهّل الصيانة.

الخلاصة

  • المُنشِئ يُهيّئ كائنًا جديدًا. لا يملك نوع إرجاع ويطابق اسم الفئة.
  • يُوفَّر المُنشِئ الافتراضي مجانًا حين لا تكتب أيًا؛ يختفي حالما تكتب مُنشِئًا واحدًا.
  • المُنشِئات ذات الوسيطات تُجبر على تقديم البيانات الضرورية عند الإنشاء.
  • this.field يُميّز حقلًا عن وسيطة تحمل نفس الاسم داخل مُنشِئ أو أسلوب.
  • this(...) يُسلسل مُنشِئًا إلى آخر في نفس الفئة ويجب أن يكون أول سطر.