الفئات المتداخلة في Java: من أين بدأ كل شيء؟
تخيل: أنت تكتب كودًا بلغة Java، وفجأة تدرك أن فئة واحدة مرتبطة منطقيًا بأخرى بشكل لا ينفصم. على سبيل المثال، Car و Engine. المحرك لا يوجد بمفرده - فهو جزء من السيارة. كيف يمكن نمذجة ذلك بشكل جميل وصحيح في Java؟ الإجابة هي الفئات المتداخلة (nested classes).
موضوع فئة Java الداخلية والفئة المتداخلة الثابتة هو من أكثر المواضيع شيوعًا على Stack Overflow. الآلاف من المطورين يخلطون بينهما: ما الفرق؟ متى نستخدم inner ومتى نستخدم static nested؟ ولماذا تم اختراعها أساسًا؟
في هذا البرنامج التعليمي، سنقوم بترتيب كل شيء. لن تتعلم فقط بناء الجملة - بل ستفهم منطق مصممي Java. هيا بنا!
ما هي الفئة المتداخلة (nested class)؟
لنبدأ بالأساسيات. الفئة المتداخلة هي فئة تم تعريفها داخل فئة أخرى. في Java، هناك أربعة أنواع من الفئات المتداخلة، لكننا اليوم مهتمون بالنوعين الأكثر شيوعًا:
- الفئة المتداخلة الثابتة (Static nested class)
- الفئة الداخلية (Inner class)، وهي الفئة المتداخلة غير الثابتة (non-static nested class)
الفرق الرئيسي هو المعدل الثابت (static modifier). إنه يغير كل شيء: من الوصول إلى الحقول إلى عمر الكائن. دعنا نفهم ذلك عمليًا.
الفئة المتداخلة الثابتة: بسيطة ومستقلة
تتصرف الفئة المتداخلة الثابتة مثل فئة خارجية عادية، لكنها "تعيش" داخل فئتها الأم. ليس لديها إمكانية الوصول إلى الحقول والطرق غير الثابتة للفئة الخارجية (إلا إذا حصلت على مرجع للكائن).
مثال من العالم الحقيقي: Database و DatabaseConfig. التكوين غير مرتبط بمثيل محدد لقاعدة البيانات.
public class Database { private String url; private static String defaultDriver = "com.mysql.cj.jdbc.Driver";
public Database(String url) { this.url = url; }
// فئة متداخلة ثابتة public static class DatabaseConfig { private String driver; private int poolSize;
public DatabaseConfig(String driver, int poolSize) { this.driver = driver; this.poolSize = poolSize; }
public void printConfig() { // لديها إمكانية الوصول فقط إلى الأعضاء الثابتة للفئة الخارجية System.out.println("Default driver: " + defaultDriver); // System.out.println(url); // خطأ! url حقل غير ثابت }
public static void staticMethodInNested() { System.out.println("طريقة ثابتة في فئة متداخلة ثابتة"); } }
public void useConfig() { // إنشاء مثيل للفئة المتداخلة الثابتة DatabaseConfig config = new DatabaseConfig("oracle.jdbc.OracleDriver", 10); config.printConfig(); }}لاحظ: لإنشاء DatabaseConfig، لا نحتاج إلى كائن Database. هذه هي الميزة الرئيسية - الاستقلالية.
متى نستخدم الفئة المتداخلة الثابتة؟
- عندما تكون الفئة المتداخلة مرتبطة منطقيًا بالفئة الخارجية، ولكنها لا تعتمد على مثيلها.
- عندما تحتاج إلى تجميع الفئات المساعدة (مثل البنائين، التكوينات، الأدوات المساعدة).
- عندما تصمم نمط Builder - مثال كلاسيكي.
الفئة الداخلية (الفئة المتداخلة غير الثابتة): مرتبطة إلى الأبد
الفئة الداخلية هي العكس تمامًا. إنها مرتبطة دائمًا بكائن معين من الفئة الخارجية. وهذا يعني:
- لديها إمكانية الوصول إلى جميع الحقول والطرق للفئة الخارجية (حتى الخاصة منها).
- لا يمكن أن توجد بدون مثيل للفئة الخارجية.
- تقوم بتخزين مرجع ضمني للكائن الخارجي (
OuterClass.this).
مثال: Car و Engine. كل سيارة