تحدثنا فيما سبق على طريقة التحميل الزائد في جافا وسنكمل الحديث في الجزء الثاني

1- السؤال هل يمكننا زيادة التحميل على الأساليب التي تختلف فقط حسب الكلمات الرئيسية الثابتة؟

لا يمكننا التحميل الزائد لطريقتين في  Java إذا كانتا تختلفان فقط عن طريق الكلمة الأساسية الثابتة (عدد المعلمات وأنواع المعلمات متماثلة). انظر برنامج جافا التالي على سبيل المثال. الرجوع إلى هذا للحصول على التفاصيل.

2- هل تدعم java التحميل الزائد للمشغل؟

على عكس ++C، لا تسمح Java بالمشغلين المحملين بشكل زائد والمحددين من قبل المستخدم. داخلياً، تقوم Java بتحميل زائد على عوامل التشغيل، على سبيل المثال، يتم تحميل + بشكل زائد للتسلسل.

3- هل يمكننا زيادة تحميل الأساليب على نوع الإرجاع؟ 

لا يمكننا التحميل الزائد حسب نوع الإرجاع. هذا السلوك هو نفسه في ++C. الرجوع إلى هذا للحصول على التفاصيل.

التحميل الزائد للأسلوب والخطأ الفارغ في java

من الشائع جداً في Java استخدام أساليب التحميل الزائد. يوجد أدناه برنامج Java مثير للاهتمام. 

public class Test

{

    // Overloaded methods

    public void fun(Integer i)

    {

        System.out.println(“fun(Integer ) “);

    }

    public void fun(String name)

    {

        System.out.println(“fun(String ) “);

    }

    // Driver code 

    public static void main(String [] args)

    {

        Test mv = new Test();

        // This line causes error

        mv.fun(null);

    }

}

السبب وراء حصولنا على خطأ وقت الترجمة في integer السيناريو أعلاه هو أنَّ وسيطات الطريقة  Integer وString  كلاهما ليسا من أنواع البيانات البدائية في Java. وهذا يعني أنهم يقبلون القيم الخالية. عندما نمرر قيمة فارغة إلى الطريقة 1، يرتبك المترجم بشأن الطريقة التي يجب عليه تحديدها، حيث أنَّ كلاهما يقبل القيمة الخالية. لن يحدث خطأ وقت الترجمة هذا إلا إذا قمنا بتمرير قيمة فارغة عن عمد. على سبيل المثال، راجع السيناريو أدناه الذي نتبعه بشكل عام أثناء البرمجة.

public class Test

{

    // Overloaded methods

    public void fun(Integer i)

    {

        System.out.println(“fun(Integer ) “);

    }

    public void fun(String name)

    {

        System.out.println(“fun(String ) “);

    }

    // Driver code

    public static void main(String [] args)

    {

        Test mv = new Test();

        Integer arg = null;

        // No compiler error

        mv.fun(arg);

    }

}

(Funinteger): في السيناريو أعلاه، إذا كانت قيمة  “arg” فارغة بسبب نتيجة التعبير، فسيتم تمرير القيمة الخالية إلى الطريقة 1. هنا لن نحصل على خطأ في وقت الترجمة لأننا نحدد أنَّ الوسيطة من النوع Integer وبالتالي يختار المترجم الطريقة 1 Integer i وسينفذ التعليمات البرمجية الموجودة داخل ذلك. ملاحظة: لن تستمر هذه المشكلة عندما تكون وسيطات الطريقة التي تم تجاوزها من نوع البيانات البدائية، لأنَّ المترجم سيختار الطريقة الأنسب وينفذها.

4- طريقة التحميل الزائد varargs والغموض في جافا 

يسمح التحميل الزائد لطرق مختلفة بأن يكون لها نفس الاسم، ولكن التوقيعات المختلفة حيث يمكن أن يختلف التوقيع حسب عدد معلمات الإدخال أو نوع معلمات الإدخال أو كليهما. يمكننا التحميل الزائد لطريقة تأخذ وسيطة ذات طول متغير باتباع الطرق التالية: 

– الحالة الأولى: الأساليب التي تحتوي على معلمات java فقط 

في هذه الحالة تستخدم varargs اختلاف النوع لتحديد الطريقة المحملة بشكل زائد التي سيتم الاتصال بها إذا كان توقيع احدى الطرق أكثر تحديدا من الاخر فستختاره دون أخطاء. 

public class varargsDemo 

    public static void main(String[] args) 

    { 

        fun(); 

    } 

    //varargs method with float datatype 

    static void fun(float… x) 

    { 

        System.out.println(“float varargs”); 

    } 

    //varargs method with int datatype 

    static void fun(int… x) 

    { 

        System.out.println(“int varargs”); 

    } 

    //varargs method with double datatype 

    static void fun(double… x) 

    { 

        System.out.println(“double varargs”); 

    } 

تحدد القواعد التالية العلاقة المباشرة بين الأنواع الأولية في هذه الحالة: 

Double>float

Float>long

Long>integer

Int>char

Int>short

Short>byte

– الحالة الثانية: الأساليب التي تحتوي على verargs مع معلمات أخرى

في هذه الحالة تستخدم كلا من عدد الوسائط ونوع الوسائط لتحديد الطريقة التي سيتم الاتصال بها فيما يلي برنامج java الذي سيقوم بتحميل (fun) بشكل زائد ثلاث مرات. 

class Test  

    // A method that takes varargs(here integers). 

    static void fun(int … a)  

    { 

        System.out.print(“fun(int …): ” + 

                “Number of args: ” + a.length + 

                ” Contents: “); 

        // using for each loop to display contents of a 

        for(int x : a) 

            System.out.print(x + ” “); 

        System.out.println(); 

    } 

    // A method that takes varargs(here booleans). 

    static void fun(boolean … a) 

    { 

        System.out.print(“fun(boolean …) ” + 

                “Number of args: ” + a.length + 

                ” Contents: “); 

        // using for each loop to display contents of a 

        for(boolean x : a) 

            System.out.print(x + ” “); 

        System.out.println(); 

    } 

    // A method takes string as a argument followed by varargs(here integers). 

    static void fun(String msg, int … a)  

    { 

        System.out.print(“fun(String, int …): ” + 

                msg + a.length + 

                ” Contents: “); 

        // using for each loop to display contents of a 

        for(int x : a) 

            System.out.print(x + ” “); 

        System.out.println(); 

    } 

    public static void main(String args[]) 

    { 

        // Calling overloaded fun() with different  parameter 

        fun(1, 2, 3); 

        fun(“Testing: “, 10, 20); 

        fun(true, false, false); 

    } 

الغموض verargs

في بعض الأحيان يمكن أن تنتج أخطاء غير متوقعة عند التحميل الزائد لأسلوب يأخذ وسيطة ذات طول متغير. تتضمن هذه الأخطاء غموضاً لأنَّ كلتا الطريقتين مرشحتان صالحتان للاستدعاء. لا يمكن للمترجم تحديد الأسلوب الذي سيتم ربط استدعاء الأسلوب به.

5- التحميل الزائد لطريقة Arity المتغيرة في جافا

سنناقش هنا هذه الطريقة وكيف يمكننا زيادة التحميل على هذا النوع من الطرق لذلك دعونا أولاً نفهم ماهي الطريقة المتغيرة والتي تسمى arity وصياغتها. يمكن للطريقة أن تأخذ عدداً من المتغيرات من النوع المحدد.

– التحميل الزائد للطريقة أو تعدد الأشكال المخصص أو تعدد الأشكال الثابت:

يتفاعل التحميل الزائد مع طرق متعددة من نفس الفئة تحمل أسماء متطابقة ولكن لها توقيعات طريقة مختلفة. تتيح لك إعادة التحميل وصف نفس العملية بطرق مختلفة لبيانات مختلفة. 

يُطلق عليه أحياناً تعدد الأشكال الساكن، لكنه في الواقع ليس تعدد الأشكال. هذا ليس أكثر من مجرد وجود طريقتين بنفس الأسماء، ولكن قائمة مختلفة من الوسائط. إعادة التشغيل لا علاقة لها بالميراث وتعدد الأشكال. والطريقة المحملة بشكل زائد ليست مثل الطريقة التي تم تجاوزها على الإطلاق. تعدد الأشكال البارامترية من خلال التوليد في JAVA عند الإعلان عن فئة، يمكن ربط حقل الاسم بأنواع مختلفة، ويمكن ربط اسم الطريقة بمعلمات وأنواع إرجاع مختلفة. تدعم JAVA تعدد الأشكال البارامترية باستخدام الأدوية العامة.

لماذا لا يمكننا تجاوز الطريقة الثابتة في java؟

يعتمد التجاوز على وجود مثيل للفئة. فكرة تعدد الأشكال هي أنه يمكنك إنشاء فئة فرعية، والكائنات التي تنفذها تلك الفئات الفرعية سوف تتصرف بشكل مختلف مع نفس أساليب الفئة الأصلية (يتم تجاوزها في الفئات الفرعية). لا ترتبط الطريقة الثابتة بأي مثيلات للفئة، لذلك لا يمكن تطبيق مفهوم التجاوز نفسه. استرشد منشئو جافا باعتبارين أثرا في هذا النهج. أولاً، هناك مشاكل في تنفيذ التعليمات البرمجية؛ كان هناك الكثير من الانتقادات لـ  Smalltalk لكونها بطيئة (كان جمع البيانات المهملة وتعدد الأشكال جزءاً من هذه المشكلة)، وتم تصميم JAVA  لتجنب ذلك. الاعتبار الثاني كان القرار بأن الجمهور المستهدف لـ JAVA سيكون مطوري ++C. كان وجود الأساليب الثابتة تعمل بهذه الطريقة مألوفاً جداً لمبرمج ++C كما أدى إلى تسريع الأمور نظراً لعدم وجود حاجة للصعود إلى التسلسل الهرمي للفصل لمعرفة الطريقة التي يجب الاتصال بها. تذهب مباشرة إلى الفصل وتتصل بطريقة محددة.

6- مزايا وعيوب طريقة التحميل الزائد في جافا 

طرق التحميل الزائد هي طرق في نفس الفئة تشترك في نفس الاسم ولكنها تقبل أنواع متغيرات مختلفة كوسائط. على سبيل المثال، قد يحتوي الفصل على طريقتين مختلفتين “add”: أحدهما يقبل قيمتين مزدوجتي (add double a، double b)، وآخر يقبل قيمتين صحيحتين (add int a، int b). يقرر الكمبيوتر تلقائياً الطريقة التي يتم الاتصال بها في وقت التشغيل بناءً على أنواع المتغيرات التي يتم تمريرها إلى الطريقة.

– المرونة: 

تمنح الطرق ذات التحميل الزائد المبرمجين المرونة لاستدعاء طريقة مماثلة لأنواع مختلفة من البيانات. إذا كنت تعمل على برنامج رياضيات، على سبيل المثال، يمكنك استخدام التحميل الزائد لإنشاء عدة فئات “مضاعفة”، كل منها يضاعف عددًا مختلفاً من نوع الوسيطة: الأبسط “اضرب (int a, int b)” يضرب اثنين أعداد صحيحة. الطريقة الأكثر تعقيدًا “اضرب (ضعف a، int (b, int c تضرب ضعفاً واحداً في عددين صحيحين – يمكنك بعد ذلك استدعاء “الضرب” على أي مجموعة من المتغيرات التي قمت بإنشاء طريقة محملة بشكل زائد والحصول على النتيجة المناسبة.

– المنشئون:

يتم استخدام التحميل الزائد أيضاً على المُنشئين لإنشاء كائنات جديدة نظراً لكميات مختلفة من البيانات. على سبيل المثال، يمكنك استخدام التحميل الزائد لإنشاء ثلاثة مُنشئين مختلفين لكائن “منزل” برقم المنزل واسم الشارع ومتغيرات اللون. أبسط مُنشئ ”(House )” لا يأخذ أي وسيطات وينشئ منزلاً بمتغيرات افتراضية أو فارغة. ينشئ المُنشئ الأكثر تعقيداًHouse ”(int)” houseNumber، String streetName منزلًا برقم المنزل المحدد واسم الشارع، ولكن بلون افتراضي أو فارغ. يُنشئ المُنشئ الأكثر تعقيداً “House (int houseNumber, String streetName, String color)” منزلاً به جميع المعلومات المحددة، دون ترك أي شيء افتراضياً. يمكنك بعد ذلك إنشاء كائن منزل بناءً على المعلومات المتاحة حالياً، مع ترك المعلومات غير المتاحة فارغة أو افتراضياً.

– مراجع غامضة: 

يجب أن تستخدم الطرق ذات التحميل الزائد أعداداً أو أنواعاً مختلفة من الوسيطات لتجنب الغموض. إذا قمت بإنشاء طريقتين في نفس الفئة لهما نفس الاسم وقبلت عددين صحيحين كوسيطات، فلن يتمكن مترجم  Java من التمييز بين الاثنين، حتى إذا كانت متغيرات الإدخال لها أسماء مختلفة. على سبيل المثال، لا يمكن أن توجد الطريقة ”(add int a, int b)”في نفس الفئة مثل الطريقة add int c, int d)”).

– أنواع الإرجاع:

يجب تحديد نوع الإرجاع لكل طريقة محملة بشكل زائد. يمكن أن يكون للطرق أنواع إرجاع مختلفة على سبيل المثال، ”(add int a, int b)”  قد ترجع عدداً صحيحاً ، بينما ”(add double a, double b)” ترجع ضعفاُ. ومع ذلك، لا تستطيع  Java التمييز بين طريقتين مختلفتين بناءً على نوع الإرجاع. لذلك، int” ضرب (ضعف أ، مزدوج ب)” لا يمكن أن توجد في نفس الفئة مثل ”مضاعفة (ضعف أ، ضعف ب)”.

7- من المفاهيم الأساسية للبرمجة الشيئية التي لم نذكرها بعد

– الوراثة inheritance:

الوراثة هي عملية دمج السلوك (أي الأساليب) والحالة (أي المتغيرات) للفئة الأساسية في فئة مشتقة بحيث تصبح متاحة في تلك الفئة المشتقة. الميزة الرئيسية للميراث هي أنه يوفر آلية رسمية لإعادة استخدام الكود ويتجنب الازدواجية. تعمل الفئة الموروثة على توسيع وظائف التطبيق عن طريق نسخ سلوك الفئة الأصلية وإضافة وظائف جديدة. وهذا يجعل الكود مقترنًا للغاية. إذا كنت ترغب في تغيير الفئة الفائقة، فسيتعين عليك معرفة جميع تفاصيل الفئات الفرعية حتى لا تكسر الكود. الوراثة هي شكل من أشكال إعادة استخدام البرامج حيث يتم إنشاء فئة جديدة (فئة فرعية) من فئة موجودة (فئة فائقة) تعمل على توسيع وظائفها وتستخدم بعض خصائص الفئة الفائقة. لذلك، إذا كان لديك فئة أصل ثم ظهرت فئة فرعية، فإنَّ الطفل يرث كل الأشياء التي يمتلكها الوالد.

المزايا: 

1- تحسين اعادة استخدام التعليمات البرمجية. 

2- وحدات الكود. 

3- يتم استبعاد التكرار.

4- يتم انشاء العلاقة المنطقية “هو “(هو شخص ما، شيء ما).

العيوب: 

مقترنة بإحكام: تعتمد الفئة الفرعية على تنفيذ فئة أصل، مما يجعل الكود مقترنا بإحكام. 

– التجريد :abstraction

التجريد يعني تصميم الفئات بناءً على واجهاتها ووظائفها، دون مراعاة تفاصيل التنفيذ. تمثل الفئة المجردة واجهات دون تضمين التنفيذ الفعلي. إنه يميز تنفيذ الكائن عن سلوكه. يعمل التجريد على تبسيط الكود عن طريق إخفاء التفاصيل غير المهمة.

المزايا: 

1- باستخدام التجريد يمكننا فصل ما يمكن تجميعه في نوع واحد.

2- يمكن تجميع الخصائص والأساليب التي تتغير بشكل متكرر في نوع منفصل، بحيث لا يخضع النوع الرئيسي للتغييرات.

3- التجريد يبسط تمثيل نماذج المجال.

– الفرق بين التجريد والتغليف:

التغليف هي استراتيجية تستخدم كجزء من التجريد. يشير التغليف إلى بنية الكائن؛ حيث تقوم الكائنات بتغليف خصائصها وإخفائها عن الوصول الخارجي. يتفاعل مستخدمو الفصل الدراسي معه باستخدام أساليبه، لكن ليس لديهم إمكانية الوصول المباشر إلى بنية الفصل. بهذه الطريقة، يلخص الفصل تفاصيل التنفيذ المتعلقة بتصميمه. التجريد هو مصطلح أكثر عمومية. ويمكن أيضاً تحقيق ذلك، من بين أمور أخرى، باستخدام الفئات الفرعية. على سبيل المثال، الفئة List(القائمة) في المكتبة القياسية هي عبارة عن تجريد لسلسلة من العناصر، مفهرسة وفقًا لمكانها في القائمة. الأمثلة المحددة للقائمة   Listهي   Array Listأو Linked List. الكود الذي يتفاعل مع القائمة List يلخص تفاصيل القائمة التي يستخدمها. في كثير من الأحيان لا يكون التجريد ممكناً دون إخفاء الحالة الأساسية باستخدام التغليف. إذا كشف الفصل عن بنيته الداخلية، فلن يتمكن من تغيير عملياته الداخلية، وبالتالي لا يمكن تجريدها.

8- ماهي الطبقة المجردة والطريقة المجردة؟

يحدث أنه أثناء التطوير تريد أن توفر الفئة الأساسية واجهة فقط للفئات المشتقة منها. أي أنك لا تريد أن يقوم أي شخص بإنشاء مثيلات للفئة الأساسية. أنت بحاجة إلى استخدام الواجهة بحيث تقوم فقط بإلقاء الكائنات إليها (وهذا عبارة عن تحويل ضمني يسمح بسلوك متعدد الأشكال). يتم تحقيق ذلك عن طريق جعل هذا الفصل مجرداً باستخدام الكلمة الأساسية abstract. وهذا يفرض بعض القيود، مثل عدم القدرة على إنشاء مثيلات لفئة مجردة؛ عند استخدام فئة مجردة، من الضروري تنفيذ أساليب مجردة. وهذا يضمن تعدد الأشكال. يمكن أن تحتوي الفئة المجردة على طرق مجردة وملموسة. إذا تم تعريف أسلوب واحد على الأقل في الفصل بأنه مجرد، فيجب أيضاً تعريف الفصل بأكمله بأنه مجرد. ومع ذلك، ليس من الضروري مراعاة القاعدة في الاتجاه المعاكس. إذا تم الإعلان عن فئة مجردة، فقد لا تحتوي على أساليب مجردة. الطريقة التي تحدد توقيعاتها فقط ولا توفر تطبيقاً تسمى مجردة. يتم ترك التنفيذ الفعلي لفئاته الفرعية، والتي توسع الطبقة المجردة. لا يمكن لكائن أن يستخدم الطريقة المجردة، بل يمكن لفئة أخرى فقط توسيعها.

9- متى يجب عليك استخدام فئة مجردة؟

تتيح لك الفئات المجردة تحديد بعض السلوكيات الافتراضية كما توفر الفئات الفرعية أي سلوك محدد. على سبيل المثال: (List list) عبارة عن واجهة، تحدد بدورها  Abstract Listالسلوك الأساسي للقائمة، والتي يمكن استخدامها كما هي أو تحسينها في فئة فرعية، على سبيل المثال، في  ArrayList (صفيف القائمة). ما هي الواجهة؟ إنَّ مفهوم الواجهة عبارة عن فئة مجردة، لكن الواجهة (المحددة بواسطة الكلمة الرئيسية interface) تذهب خطوة أخرى إلى الأمام. يمنع أي تنفيذ لطريقة أو وظيفة على الإطلاق. يمكنك فقط الإعلان عن طريقة أو وظيفة، ولكن لا يمكنك توفير تنفيذها. يجب أن تهتم الفئة التي تنفذ الواجهة بالتنفيذ الفعلي. الواجهات مفيدة جداً وتستخدم على نطاق واسع في OOP. ونظراً لأنهما يشتركان في الواجهة نفسها والتنفيذ، فإنهما يوفران العديد من المزايا لاستخدامهما:

1- تعدد الميراث.

2- اقتران فضفاض: هناك تجريد للعملية مثل الطبقات: JDBC,JTA JPA, ويمكن ان يكون التنفيذ الملموس أي شيء.

3- لم يتم تنفيذ برامج الواجهة.

4- تعدد اشكال الربط الديناميكي: يتم عرض واجهة برمجة الكائن دون الكشف عن تنفيذه العملي.

5- مستويات مجردة وفصل الوظائف.

10- الفرق بين الواجهة والطبقة المجردة:

  • الواجهة هي علاقة تعاقدية مع الفئات التي تنفذ هذه الواجهة تنص على أن التنفيذ يتم بالطريقة التي تحددها الواجهة.
  • تحدد الفئة المجردة بعض السلوك العام وتطلب من فئاتها الفرعية تحديد سلوك غير نمطي أو محدد لفئتها.
  • يمكن تعيين أساليب واعضاء فئة مجردة باستخدام أي معدل وصول وفي المقابل يجب أن تكون جميع أساليب الواجهة عامة. 
  • عند وراثة فئة مجردة يجب على الفئة التابعة تعريف الأساليب المجردة بينما يمكن للواجهة أن ترث واجهة اخرى دون تحديد أساليبها بالضرورة.
  • يمكن للفئة التابعة توسيع فئة مجردة واحدة فقط، ولكن يمكن للواجهة أن تمتد أو يمكن للفئة تنفيذ العديد من الواجهات الأخرى.
  • يمكن للفئة التابعة أن تحدد طرقا مجردة بنفس معدل الوصول أو أقل تقييداً ولكن يجب أن تحدد الفئة التي تنفذ الواجهة طرقا بنفس مستوى الرؤية. 
  • لا تحتوي الواجهة على منشئات بينما تحتوي الفئة المجردة على ذلك. 
Facebook
Twitter
YouTube
LinkedIn
Instagram