الرجوع
تسجيل الدخول

Overloading vs Overriding

6/5/2025 4 1

الفرق بين التحميل الزائد (Overloading) والتجاوز (Overriding) في جافا

التحميل الزائد (Overloading)

  • التعريف: يحدث التحميل الزائد عندما يكون هناك عدة ميثودز في نفس الكلاس لها نفس الاسم ولكن قوائم معاملات (باراميترز) مختلفة (عدد مختلف، أنواع مختلفة، أو ترتيب مختلف). يتم تحديد الدالة المستخدمة أثناء وقت الترجمة compile time (تعدد الأشكال الثابت - Static Polymorphism).

  • النقاط الرئيسية:

    • يجب أن تختلف الميثودز في عدد المعاملات، نوعها، أو ترتيبها.

    • نوع القيمة المُعادة (Return Type) وحده لا يكفي لتمييز الدوال المُحمّلة (ما يفرق).

    • يمكن أن يحدث في نفس الكلاس أو في كلاس فرعي.

    • لا يتطلب الوراثة.

مثال على التحميل الزائد

class Calculator {
    // دالة محمّلة زائديًا: نفس الاسم، معلمات مختلفة الأنواع
    public int add(int a, int b) {
        return a + b;
    }

    // دالة محمّلة زائديًا: أنواع معلمات مختلفة (double)
    public double add(double a, double b) {
        return a + b;
    }

    // دالة محمّلة زائديًا: عدد معلمات مختلف
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

في هذا المثال:

  • الدالة add تم تحميلها زائديًا بمعاملات مختلفة.

  • يقرر المترجم (Compiler) أي دالة سيتم استدعاؤها بناءً على المعلمات الممررة.

التجاوز (Overriding)

  • التعريف: يحدث التجاوز عندما يوفر كلاس فرعي كود مختلف لميثود موجودة مسبقًا في الكلاس الأب. يتم تحديد الدالة المستخدمة أثناء وقت التشغيل runtime (تعدد الأشكال الديناميكي - Dynamic Polymorphism).

  • النقاط الرئيسية:

    • يجب أن يكون للميثود في الكلاس الفرعي نفس الاسم، نفس قائمة المعاملات، ونفس نوع القيمة المُعادة كما في الكلاس الأب.

    • يجب أن تكون الميثود موروثة من الكلاس الأب.

    • يمكن استخدام التعليق التوضيحي @Override للتأكد من أن التجاوز تم بشكل صحيح.

    • معدّلات الوصول (Access Modifiers) في الكلاس الفرعي لا يمكن أن تكون أكثر تقييدًا من الدالة في الكلاس الأب.

مثال على التجاوز

 

class Animal {
    public void makeSound() {
        System.out.println("صوت حيوان عام");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("نباح!");
    }
}

class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.makeSound(); // يستدعي makeSound() الخاص بـ Dog - نباح!
    }
}

 

في هذا المثال:

  • الدالة makeSound في Dog تتجاوز الدالة الموجودة في Animal.

  • أثناء التشغيل، يقرر JVM استدعاء تنفيذ Dog بسبب تعدد الأشكال.

مثال معقد للتجاوز

إليك مثالًا يوضح خطأ شائعًا قد يؤدي إلى التحميل الزائد بدلاً من التجاوز:

class Parent {
    public void display(String s) {
        System.out.println("الأب: " + s);
    }
}

class Child extends Parent {
    // خطأ: نوع معلمة مختلف (Object بدلاً من String)
    public void display(Object o) {
        System.out.println("الابن: " + o);
    }
}

class Main {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.display("اختبار"); // يستدعي display(String) الخاص بـ Parent
    }
}

لماذا هذا معقد؟

  • الدالة display(Object) في Child لا تتجاوز display(String) في Parent لأن أنواع المعاملات مختلفة. بدلاً من ذلك، تقوم بالتحميل الزائد.

  • الناتج هو الأب: اختبار لأن الدالة في Child لا يتم استدعاؤها بسبب عدم وجود تجاوز.

  • هذا خطأ شائع عندما ينوي المبرمج التجاوز ولكنه يقوم بالتحميل الزائد عن طريق الخطأ.

استخدام @Override للتحقق من التجاوز

التعليق التوضيحي @Override هو فحص في وقت الترجمة يضمن أن الدالة تقوم فعلاً بتجاوز دالة من الكلاس الأب أو واجهة (Interface). إذا لم تتجاوز الدالة أي شيء، سيعطي المترجم خطأ.

مثال باستخدام @Override

 

class Parent {
    public void display(String s) {
        System.out.println("الأب: " + s);
    }
}

class Child extends Parent {
    // سيؤدي هذا إلى خطأ في وقت الترجمة
    @Override
    public void display(Object o) { // خطأ: الدالة لا تتجاوز دالة من الكلاس الأب
        System.out.println("الابن: " + o);
    }
}

 

كيف يساعد @Override؟

  • إذا أضفت @Override إلى دالة لا تتجاوز دالة من الكلاس الأب، سيقوم المترجم بتنبيهك (مثلاً، في المثال أعلاه، عدم تطابق نوع المعاملات يسبب خطأ).

  • هذا يمنع التحميل الزائد العرضي عندما يكون القصد هو التجاوز.

الاستخدام الصحيح لـ @Override

 

class Parent {
    public void display(String s) {
        System.out.println("الأب: " + s);
    }
}

class Child extends Parent {
    @Override
    public void display(String s) { // تتجاوز بشكل صحيح
        System.out.println("الابن: " + s);
    }
}

class Main {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.display("اختبار"); // يستدعي display الخاص بـ Child - الابن: اختبار
    }
}

 

الفرق الرئيسي بين التحميل الزائد والتجاوز

الميزة

التحميل الزائد

التجاوز

النطاق

نفس الكلاس أو الكلاس الفرعي

الكلاس الفرعي فقط

توقيع الدالة

نفس الاسم، معاملات مختلفة

نفس الاسم، المعاملات، ونوع القيمة المُعادة

تعدد الأشكال

وقت الترجمة (ثابت)

وقت التشغيل (ديناميكي)

الوراثة

غير مطلوبة

مطلوبة

معدّلات الوصول

لا قيود

لا يمكن أن تكون أكثر تقييدًا

التعليق التوضيحي

لا يوجد

يمكن استخدام @Override