GagorAcadmey

تعلم برمجة تطبيقات الاندرويد من الصفر حتي الاحتراف

آخر المواضيع

الاثنين، 3 سبتمبر 2018

الوراثة في جافا

مفهوم الوراثة

وراثة: تعني Inheritance
في جافا, الكلاس يمكنه أن يرث من كلاس آخر, و بالتالي يحصل على الدوال و المتغيرات الموجودة في هذا الكلاس.

مفهوم Superclass و Subclass

    الكلاس الذي يرث من كلاس آخر يسمى Subclass ً او الكلاس الابن وايضا يسمي ( derived class, extended class أو child class ). الكلاس الذي يورث محتوياته لكلاس آخر يسمى Superclass اً او الكلاس الاب وايضا يسمي( base class أو parent class )

مثال

الآن لنفترض أننا قمنا بتعريف كلاس إسمه A يحتوي على متغير إسمه x و دالة إسمها printA().
بعدها قمنا بإنشاء كلاس جديد فارغ إسمه B و قلنا أنه يرث من الكلاس A. إذاً هذا يعني أن الكلاس B أصبح يملك نسخة من جميع المتغيرات و الدوال الموجودة في الكلاس A.

إنتبه

الـ Subclass يرث كل شيء موجود في الـ Superclass بشكل تلقائي ما عدا الـكونستركتور.
مع العلم أنه يمكن استدعاء كونستركتور الـ Superclass من الـ Subclass بواسطة الكلمة super التي سنشرحها لاحقاً في هذا الدرس.

الكلمة extends

الكلمة extends هي اساس الوراثة فعند وضع هذه الكلمة بجانب اسم الكلاس هذا يعني ان هذا الكلاس يرث من كلاس أخر

مكان وضع الكلمة extends

نضع الكلمة extends بعد إسم الكلاس, ثم نضع بعدها إسم الكلاس الذي نريد الوراثة منه.
الكود التالي يعني أن الكلاس B يرث من الكلاس A.
class A {
}
class B extends A {
}

إنتبه: في حال كنت تحاول الوراثة من كلاس غير موجود سيظهر لك الخطأ التالي: java.lang.ExceptionInInitializerError

مثال

الآن لنفترض أننا قمنا بتعريف كلاس إسمه A و دالة إسمها printHello() and printWorld. بعدها قمنا بإنشاء كلاس جديد فارغ إسمه B و قلنا أنه يرث من الكلاس A. إذاً هذا يعني أن الكلاس B أصبح يملك نسخة من جميع المتغيرات و الدوال الموجودة في الكلاس A.
بعد إنشاء هذا الكلاس, سنقوم بإنشاء الكلاس Test لتجربته.
package inheritance;
public class A {
  public void printHello() {
   System.out.println("Hello");
 }
 public void printWorld() {
 System.out.println("World");
  }
}

package inheritance;
// A يرث المتغيرات و الدوال الموجودة في الكلاس B هنا قلنا أن الكلاس
public class B extends A {
// A سيحتوي المتغيرات و الدوال الموجودة في الكلاس B إذاً أي كائن من الكلاس
}

package inheritance;
  public class Test {
    public static void main(String[] args) {
    // أم لا A لنتأكد إذا كان يحتوي على الأشياء الموجودة في الكلاس B هنا قمنا بإنشاء كائن من الكلاس
    B b = new B();
    //A من الكلاس B  يتم إستدعاء الدوال التي ورثها الكلاس 
    b.printHello();
    b.printWorld();
 }
}

سنحصل على النتيجة التالية عند التشغيل.
Hello
World

الكلمة super

الكلمة super تستخدم للأهداف التالية:

    للتمييز بين الأشياء (المتغيرات و الدوال) الموجودة في الـ Superclass و Subclass في حال كانت الأسماء مستخدمة في كلا الكلاسَين.

    لإستدعاء الـكونستركتور الموجود في الـ Superclass.

إذاً الكلمة super تستخدم لإستدعاء الأشياء الموجودة في الـ Superclass.

طريقة استخدام الكلمة super لإستدعاء متغير من الـ Superclass

نضع الكلمة super, بعدها نقطة, ثم نضع إسم المتغير الذي نريد إستدعائه من الـ Superclass.
super.variableName
لنفترض أننا قمنا بتعريف كلاس إسمه A يحتوي على متغير إسمه x.
بعدها قمنا بإنشاء كلاس إسمه B يرث من الكلاس A و يحتوي على متغير إسمه x, و دالة إسمها printBoth() تطبع قيمة x الموجود في A و قيمة x الموجود في B بطريقتين.
بعدها سنقوم بإنشاء الكلاس Test لتجربة الكود.
A.java
package inheritance;
public class A {
public int x = 5;
}

B.java
package inheritance;
public class B extends A { // A يرث من الكلاس B هنا قلنا أن الكلاس
  public int x = 20;// مع وضع قيمة مختلفة له A هنا قمنا بتعريف نفس المتغير الموجود في الكلاس
  public void printBoth() {// عند استدعاء هذه الدالة سيتم عرض الأشياء التالية
    System.out.println("x in B contain: " +x);       // B الموجودة في الكلاس x هنا سيتم عرض قيمة الـ
    System.out.println("x in B contain: " +this.x);    // B الموجودة في الكلاس x هنا سيتم عرض قيمة الـ
    System.out.println("x in A contain: " +super.x);    // A الموجودة في الكلاس x هنا سيتم عرض قيمة الـ
  }
}

Test.java
package inheritance;
public class Test {
  public static void main(String[] args) {
    B b = new B();   // منه printBoth() من أجل إستدعاء الدالة B هنا قمنا بإنشاء كائن من الكلاس
    b.printBoth();   // هنا قمنا باستدعائها
  }
}
سنحصل على النتيجة التالية عند التشغيل.
x in B contain: 20
x in B contain: 20
x in A contain: 5


طريقة استخدام الكلمة super لإستدعاء دالة من الـ Superclass

نضع الكلمة super, بعدها نقطة, ثم نضع إسم الدالة التي نريد إستدعائها من الـ Superclass.
super.methodName()

تذكر


لا تنسى وضع الكلمة @Override قبل إسم الدالة التي ورثها الـ Subclass في الأصل من الـ Superclass و لكنه قام بتعريفها من جديد.

الآن لنفترض أننا قمنا بتعريف كلاس إسمه A يحتوي على دالة إسمه print().
بعدها قمنا بإنشاء كلاس إسمه B يرث من الكلاس A و يحتوي على دالة إسمها print() أيضاً, بالإضافة إلى دالة إسمها printBoth() تستدعي الدالة print() الموجودة في A و تستدعي الدالة print() الموجودة في B بطريقتين.
بعدها سنقوم بإنشاء الكلاس Test لتجربة الكود.
A.java
package inheritance;
public class A {
  public void print() {
    System.out.println("This is print() method from the class A");
 }
}
B.java
package inheritance;
public class B extends A {     // A يرث من الكلاس B هنا قلنا أن الكلاس
  // قبلها, مع وضع جملة مختلفة في دالة الطباعة @Override لذلك وضعنا A هنا قمنا بتعريف نفس الدالة الموجودة في الكلاس
  @Override
  public void print() {
    System.out.println("This is print() method from the class B");
     }
  // هنا قمنا بتعريف دالة مهمتها فقط إستدعاء الدوال الموجودة بداخلها
  public void printBoth() {
    print();        // B الموجودة في الكلاس print() هنا سيتم إستدعاء الدالة
    this.print();     // B الموجودة في الكلاس print() هنا سيتم إستدعاء الدالة
    super.print();     // A الموجودة في الكلاس print() هنا سيتم إستدعاء الدالة
    }
}

Test.java
package inheritance;
public class Test {
  public static void main(String[] args) {
    B b = new B();   // منه printBoth() من أجل إستدعاء الدالة B هنا قمنا بإنشاء كائن من الكلاس
    b.printBoth();   // هنا قمنا باستدعائها
   }
}

سنحصل على النتيجة التالية عند التشغيل.
This is print() method from the class B
This is print() method from the class B
This is print() method from the class A

إنتبه

في حال قام الـ Subclass بتعريف دالة كانت أصلاً موجودة في الـ Superclass يجب كتابة الكلمة @Override قبلها مباشرةً, و هكذا سيفهم المترجم أن الـ Subclass قام بتعريف الدالة التي ورثها من الـ Superclass من جديد.

طريقة استخدامها عند استدعاء كونستركتور

يمكن استدعاء كونستركتور الـ Superclass من داخل كونستركتور الـ Subclass من خلال الكلمة super.
super()// عند استدعاء كونستركتور فارغ نكتب هكذا فقط
// أو هكذا
super( parameter List )  // عند استدعاء كونستركتور يحتوي على باراميترات, عليك تمرير قيم له.

في حال كان الـ Superclass يملك فقط كونستركتور لا يحتوي أي باراميترات (أي مثل كونستركتور إفتراضي), سيقوم المترجم باستدعائه بشكل تلقائي في الـ Subclass حتى لو لم تقم باستدعائه بنفسك.

و في حال كان الـ Superclass يملك أكثر من كونستركتور, ستكون مجبر على تعريف كونستركتور في الـ Subclass يستدعي أي كونستركتور من الـ construtors الموجودين في Superclass.
في هذا المثال قمنا بتعريف كلاس إسمه A يحتوي على متغيرين x و y بالإضافة إلى كونستركتور لا يقبل أي باراميتر و مهمته بتوليد قيم لهما فقط.
بعدها قمنا بإنشاء كلاس إسمه B يرث من الكلاس A.
بعدها سنقوم بإنشاء الكلاس Test لتجربة الكود.
A.java
package inheritance;
public class A {
  public int x;
  public int y;
  public string WelcomeWorld;
  // A هنا قمنا بتعريف الكونستركتور الإفتراضي للكلاس   
  // سيتم تنفيذه بشكل تلقائي في أي كلاس يرث منه .A و بما أنه لا يوجد غيره في الكلاس
  public  A() {
    x = 10;
    y = 100;
    WelcomeWorld = "Hello World!";
    }
}

B.java
package inheritance;
public class B extends A {// A يرث من الكلاس B هنا قلنا أن الكلاس
  // أي عند إنشاء كائن منه ,B عند استدعاء الكونستركتور الإفتراضي للكلاس
  // حتى و إن لم نقم باستدعائه A سيتم إستدعاء الكونستركتور الإفتراضي الموجود في الكلاس
}

Test.java
package inheritance;
public class Test {
  public static void main(String[] args) {
    // A من أجل عرض قيم المتغيرات التي ورثها من الكلاس B هنا قمنا بإنشاء كائن من الكلاس
    B b = new B();
    System.out.println("x: " + b.x);
    System.out.println("y: " + b.y);
    System.out.println("WelcomeWorld: " + b.WelcomeWorld);
   }
}
نتيجة التنفيذ :
x: 10
y: 100
WelcomeWorld: Hello World!

في هذا المثال قمنا بكتابة نفس الكود السابق مع إستدعاء كونستركتور الكلاس A في كونستركتور الكلاس B.
تذكر أنه لا يوجد داعي لكتابة هذا الكود لأن مترجم لغة جافا يفعل ذلك بشكل تلقائي عنك.
A.java
package inheritance;
public class A {
  public int x;
  public int y;
  public String WelcomeWorld;
  // A هنا قمنا بتعريف الكونستركتور الإفتراضي للكلاس
  // سيتم تنفيذه بشكل تلقائي في أي كلاس يرث منه .A و بما أنه لا يوجد غيره في الكلاس
  public  A() {
    x = 10;
    y = 100;
    WelcomeWorld = "Hello World!";
    }
}

B.java
package inheritance;
public class B extends A {  // A يرث من الكلاس B هنا قلنا أن الكلاس
// نفس الشرح السابق تماماً, لكن هنا يمكنك القول أننا ذكرنا ما حدث بتفصيل
  public  B() {       // B عند استخدام هذا الكونستركتور لإنشاء كائن من الكلاس
    super();       // A سيتم إستدعاء كونستركتور الكلاس
   }
}
Test.java
package inheritance;
public class Test {
  public static void main(String[] args) {
    // A من أجل عرض قيم المتغيرات التي ورثها من الكلاس B هنا قمنا بإنشاء كائن من الكلاس
    B b = new B();
    System.out.println("x: " + b.x);
    System.out.println("y: " + b.y);
    System.out.println("WelcomeWorld: " + b.WelcomeWorld);
     }
}
سنحصل على النتيجة التالية عند التشغيل.
x: 10
y: 100
WelcomeWorld: Hello World!
في هذا المثال قمنا بكتابة نفس الكود السابق مع تعريف متغير جديد في الكلاس B إسمه z و إعطائه قيمة في الكونستركتور, و تغيير قيمة المتغير x في كونستركتور الكلاس B.
عند تجربة الكود سنقوم بعرض قيم المتغيرات الموجودة في A و B.
الهدف الحقيقي هنا إيصال فكرة أن الـ Subclass يمكنه إستخدام الأشياء التي ورثها من الـ Superclass كما يشاء.
A.java
package inheritance;
public class A {
  public int x;
  public int y;
  // A هنا قمنا بتعريف الكونستركتور الإفتراضي للكلاس  
  // سيتم تنفيذه بشكل تلقائي في أي كلاس يرث منه .A و بما أنه لا يوجد غيره في الكلاس
  public  A() {
    x = 50;
    y = 100;
   }
}

B.java
package inheritance;
public class B extends A {// A يرث من الكلاس B هنا قلنا أن الكلاس
  public int z;// z هنا قمنا بتعريف المتغير
  public  B() {// B عند استخدام هذا الكونستركتور لإنشاء كائن من الكلاس
    super();// A سيتم إستدعاء كونستركتور الكلاس
    z = 1000;// z و سيتم إعطاء قيمة للمتغير
    x = 400;// A بالقيمة 9, مع الملاحظة أنها ستبقى 50 في أي كائن من الكلاس B في أي كائن من الكلاس x هنا سيتم تبديل قيمة المتغير
   }
}

Test.java
package inheritance;
public class Test {
  public static void main(String[] args) {
    // A من أجل عرض قيم المتغيرات التي ورثها من الكلاس B هنا قمنا بإنشاء كائن من الكلاس
    B b = new B();
    System.out.println("the result from class B:");
    System.out.println("x: " + b.x);
    System.out.println("y: " + b.y);
    System.out.println("z: " + b.z);
    System.out.println();
    // من أجل التأكد من أن قيم متغيراته لا تتأثر إذا تم تغيير نفس المتغيرات في أي كلاس يرث منه A هنا قمنا بإنشاء كائن من الكلاس
    A a = new A();
    System.out.println("the result from class A :");
    System.out.println("x: " + a.x);  // B الموجود في الكلاس x مختلفة عن قيمة المتغير A الموجود في الكلاس x لاحظ كيف أن قيمة المتغير
    System.out.println("y: " + a.y);
   }
}
نتيجة التنفيذ
the result from class B :
x: 400
y: 100
z: 1000

the result from class A :
x: 50
y: 100

أشكال الوراثة في جافا

في أي لغة برمجة, يوجد 4 أشكال أساسية للوراثة كما في الصورة التالية.

جافا لا تدعم تعدد الوراثة كما يوجد في بعض لغات البرمجة الأخرى, أي لا يمكن للكلاس الواحد الوراثة في نفس الوقت من أكثر من كلاس.
إذاً الكلاس الوحد لا يمكنه أن يفعل extends لأكثر من كلاس , بمعنى أن كل كلاس يمكنه وراثة كلاس واحد.
جافا تدعم تعدد الوراثة من خلال interface, أي من أجل الوراثة من أكثر من كلاس يجب إستخدام الكلمة interface بدلاً من class, و استخدام الكلمة implements بدلاً من extends ضمن شروط معينة. ستتعلم تعدد الوراثة في درس لاحق.

بالنسبة للوراثة المتتالية ( أو المتعددة المستويات ), دائماً آخر كلاس يرث جميع المتغيرات و الدوال الموجودة في الكلاسات الأعلى منه.

IS-A Relationship

IS-A هو مجرد أسلوب لفهم علاقة الكائنات مع بعضها. فمثلاً لنفترض أننا سنقوم بإنشاء برنامج لحفظ معلومات عن الحيوانات, يجب في البداية تجهيز كلاس أساسي يمثل جميع الخصائص المشتركة بين الحيوانات, بعدها يجب تقسيم الحيوانات إلى أربع فئات أساسية (ثدييات, زواحف, طيور, حيوانات مائية). بعدها يجب تعريف كل حيوان ضمن الفئة التي ينتمي لها.

التوضيح في الشكل البرمجي كالاتي :

// هنا قمنا بتعريف الكلاس الأساسي لجميع الحيوانات
class Animal { }
// هنا قمنا بتعريف فئات الحيوانات
class Mammals  extends Animal { }
class Reptiles extends Animal { }
class Birds    extends Animal { }
class Aquatic  extends Animal { }
// هنا قمنا بتعريف 4 حيوانات مع وضع كل حيوان ضمن فئته
class Dog      extends Mammals { }
class Snack    extends Reptiles { }
class Parrot   extends Birds { }
class Dolphin  extends Aquatic { }

العامل instanceof

العامل instanceof يستخدم لمعرفة إذا كان الكائن ينتمي إلى كلاس معين أم لا.
يرجع true في حال كان الكائن ينتمي لكلاس معين, غير ذلك يرجع false.


مثال

الآن سنقوم بكتابة الكود السابق و استخدام العامل instanceof لمعرفة الكلاسات التي ينتمي إليها الكائن.

ملاحظة: هنا قمنا بتعريف جميع الكلاسات كـ private وراء بعضهم في نفس ملف الجافا لأن جافا تسمح بذلك. لكننا لا ننصح باستخدام هذا الأسلوب في البرامج العادية.
كما أننا سنستخدم العامل instanceof في دروس لاحقة.

مثال

// هنا قمنا بتعريف الكلاس الأساسي لجميع الحيوانات
class Animal { }
 
// هنا قمنا بتعريف فئات الحيوانات
class Mammals  extends Animal { }
class Reptiles extends Animal { }
class Birds    extends Animal { }
class Aquatic  extends Animal { }
 
// هنا قمنا بتعريف 4 حيوانات مع وضع كل حيوان ضمن فئته
class Dog      extends Mammals { }
class Snack    extends Reptiles { }
class Parrot   extends Birds { }
class Dolphin  extends Aquatic { }
  
public class Main {
 
    public static void main(String[] args) {
 
// Dog هنا قمنا بإنشاء كائن من الكلاس
        Dog dog1 = new Dog();
 
// dog1 هنا قمنا باختبار الكلاسات التي ينتمي إليها الكائن
        System.out.println( dog1 instanceof Dog);
        System.out.println( dog1 instanceof Animal);
    }
}

سنحصل على النتيجة التالية عند التشغيل.

true
true

الكلاس Object

في جافا, يوجد مئات الكلاسات الجاهزة التي تم بناءها بشكل هرمي كما في الصورة التالية.

جميع الكلاسات في جافا ترث بشكل تلقائي من الكلاس Object لأنه فعلياً يأتي في رأس الهرم و بالتالي فوق الجميع.
إذاً الكلاس Object هو أعلى Superclass في جافا.
و إذا لاحظت في الدروس السابقة أن أي كلاس جديد كنا نستخدمه يحتوي على الدوال equals(), hashcode(), toString() إلخ..
سبب وجود هذه الدوال في كل كلاس كنا نستخدمه أنه ورثهم من الكلاس Object.

ليست هناك تعليقات:

إرسال تعليق

ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.

صفحتنا علي الفيسبوك

التسميات

المتواجدين حاليا