اذهب إلى المحتوى

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


أحمد النوبي

نواصل في هذا المقال استعراض أساسيات لغة جافا التي يحتاج كل مُطوّر أندرويد الإلمام بها. إذا لم تطّلع على الجزء الأول فأنصحك بقراءته أوّلا قبل مواصلة قراءة هذا المقال.

android-java.png

المصفوفات

في بعض الأحيان نحتاج إلى تخزين عدة بيانات من نفس النوع والتعامل معها، في هذه الحالة لا يتم استخدام عدة متغيرات للتعامل معها ولكن يتم استخدام المصفوفات Arrays.

فالمصفوفات مجموعة متغيرات من نفس النوع وتربطها علاقة ببعضها فيتم تخزينها داخل متغير واحد من النوع مصفوفة، ويتم تعريف المصفوفة بالشكل التالي

DataType [] arrayName = new DataType [arraySize];

فمثلا لتعريف مصفوفة من النوع int وتحتوي على 6 عناصر:

int [] numArr = new int [6];

هكذا تم حجز 6 أماكن في الذاكرة للمصفوفة numArr، وللوصول لهذه الأماكن للتخزين فيها أو التعامل مع قيمها.

numArr[0] = 10;
numArr[1] = 5;
...
numArr[5] = 3;

والعنصر الأول يبدأ من صفر وتنتهي العناصر عند الرقم 5 لتصبح ست عناصر، ويتم التعامل بعد ذلك مع عناصر المصفوفة مثل المتغيرات فمثلًا لجمع رقم ما على إحدى قيمها

numArr[3] = numArr[0] + 4;

ويتم احتساب خطأ إذا تم الوصول إلى عنصر خارج حدود المصفوفة التي تم تعريفها مثل:

numArr[7] = 2 ; //Error

وتصنف النوع السابق من المصفوفات على أنه من المصفوفات الساكنة التي عند تحديد عدد عناصرها عند تعريفها فلا يمكن زيادة هذا العدد أو إزالة عناصر من المصفوفة.

الدوال

الدالة هي مجموعة من الأوامر التي تنفذ فقط عندما نقوم باستدعائها وتستخدم للقيام بالأوامر التي يتكرر استخدامها في مواضع مختلفة في البرنامج بسهولة دون إعادة كتابة الأسطر البرمجية مجددًا مما يجعل البرنامج أكثر وضوحًا.

تتميز جافا باحتوائها على مجموعة كبيرة من الدوال الجاهزة التي يمكنك استعمالها مباشرة، كما يمكننا من إنشاء دوال خاصة تؤدي وظائف محددة.

تعريف الدوال يتم على النحو التالي

AccessModifier ReturnType methodName ( parameters List){

//Do some Actions here

}

ويحدد AccessModifier طريقة الوصول لهذه الدالة.

ونوع البيانات التي سترجعه الدالة يتم تحديده في ReturnType.

ثم يتم تحديد الاسم الخاص بالدالة، والـ parameters هي البيانات التي يتم تمريرها للدالة.

public int add( int a , int b ) {
  int sum = a + b;
  return sum;
}

في المثال السابق كلمة public تعني أن هذه الدالة يمكن استدعاؤها من أي مكان في البرنامج وهي عكس private والتي تعني أن هذه الدالة لا يمكن استدعاؤها إلا من داخل الصّنف class الذي قام بتعريفها.

بعد ذلك تم تحديد النوع الذي ستعيده الدالة عند استدعائها وهو int، والاسم الخاص بهذه الدالة add وتأخذ هذه الدالة قيمتين من النوع int لتعيد ناتج جمعهما.

لاستدعاء هذه الدالة من أي مكان داخل البرنامج يتم كتابة اسم الدالة كما بالشكل:

int result = add (10 , 15);

الأصناف

وهو الوحدة الأساسية المبني عليها باقي مفاهيم البرمجة كائنية التّوجّه، وهو عبارة عن وعاء كبير يحتوي على متغيرات ودوال وكائنات. وعند تعريف صنف Class جديد يصبح لديك نوع بيانات جديد يمكنك استخدامه مع باق الأنواع الموجودة بالفعل.

لتعريف صنف يتم كتابة كلمة class واختيار اسم له، ثم فتح أقواس تحدد بدايته ونهايته.

class ClassName {

}

تسمى المتغيرات التي يتم تعريفها داخل الصّنف بالخصائص attributes، وتسمى الدوال بالتّوابع methods (يعني سنستعمل "دالة" و "تابع" للدّلالة على نفس المفهوم).

وتسمى المتغيرات من الأصناف بالكائنات Objects، فلا يمكن إنشاء كائن دون وجود صنف له.

إذا أردنا أن نكتب برنامجًا يعبر عن مكتبة وما تحتويه من كتب فيمكن اعتبار الكتاب على أنه كائن ولإنشاء هذا الكائن ينبغي وجود Class له يحتوي على الخصائص الأساسية لجميع الكتب.

class Book{
  private String bookName;
  private String authorName;
  private int bookCode;

  public void setBookName(String name){
    bookName = name;
  }

  public String getBookName(){
    return bookName;
  }

  public void setAuthorName(String name){
    authorName = name;
  }

  public String getAuthorName(){
    return authorName;
  }

  public void setBookCode(int code){
    bookCode= code
  }

  public int getBookCode(){
    return bookCode;
  }
}

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

لاحظ أننا قمنا بتعريف التوابع كـ public وذلك حتى نستطيع الوصول لها واستدعائها من أي مكان في البرنامج.

هناك بعض الدوال التي تم تعريف نوع المُخرجات returnType لها من النوع void وتعني أنها لا تعيد شيئًا.

ولإنشاء كائن من هذا الصّنف نكتب:

Book b1 = new Book();
Book book2 = new Book();

النصف الأيسر كما اعتدنا سابقًا عند إنشاء متغير جديد، أما النصف الأيمن فيتكون من شقين كلمة new وتعني إنشاء هذا المتغير وحجز مساحة له في الذاكرة واسم الصّنف وبعده أقواس وهو ما يسمى بالـ Constructor.

ولأي من هذه الكائنات إذا أردنا وضع قيم للخصائص التي بداخلها يتم على النحو التالي:

b1.setBookName(“Learn Java”);

book2.setBookName(“Intro to programming Language”);
book2.setBookCode(101);

String name = b1.getBookName();

وهذه بعض الأمثلة لكيفية استدعاء التّوابع المختلفة من داخل class وباستخدام الكائن، لكل كائن خصائصه الخاصة لا يتشارك فيها مع باق الكائنات التي من نفس Class فلكل منها اسم كتاب يتم تخزين فيه نص معين لا يتشاركان فيه.

ولاستدعاء التوابع يتم استخدام (.) بعد اسم الكائن ثم كتابة اسم التابع وتمرير المتغيرات التي تتعامل معها إن وجدت حسب تعريفنا للتّابع داخل الصّنف.

لاحظ أن عند إنشاء صنف جديد نبدأ اسمه بحرف كبير دائمًا، ويمكنك إنشاء أي عدد من الكائنات من الصّنف كما ذكرنا في المثال السابق.

تابع البناء Constructor

تتواجد داخل كل صنف تابع خاص يُدعى Constructor يتم استدعاؤه أثناء إنشاء كائن جديد فهو تابع مهم جدًا لإنشاء الكائنات ويقوم المترجم بإنشاء هذا تابع بناء فارغ بشكل افتراضي إذا لم يتم تعريفها من قبل المطوّر. وتكتب كالتالي:

public ClassName(parameter List){
  //Do some Actions here
}

يجب أن يكون اسم تابع البناءconstructor نفس اسم الصنف ومن النوع public ويمكنك تعريف أكثر من constructor داخل نفس الصّنف ولا يوجد نوع إرجاع returnType لـلـ constructor.

يمكننا من خلال constructor إدخال قيم مباشرة في الخصائص الموجودة في الكائن بدلًا من استدعاء دالة لكل خاصية.

class Book{
  private String bookName;
  private String authorName;
  private int bookCode;
 
  public Book(String name,String author,int code){
    bookName = name;
    authorName = author;
    bookCode = code;
  }

  public String getBookName(){
    return bookName;
  }

  public String getAuthorName(){
    return authorName;
  }

  public int getBookCode(){
    return bookCode;
  }
}

في كل مرة يتم إنشاء كائن جديد، يجب استدعاء تابع البناء constructor حتى يتم إنشاء هذا الكائن.

لإنشاء كائنات بعد هذا التعديل:

Book b1 = new Book (“Learn Java”,”M.K Dave”, 150);

هنا تم تعريف كافة الخصائص لحظة إنشاء الكائن، ويتم التعامل مع هذا الكائن بشكل طبيعي كما تعاملنا معه مسبقًا.

الوراثة

يعتبر مفهوم الوراثة من أهم المفاهيم في البرمجة كائنية التّوجّه ويعني يمكننا إنشاء أصناف ترث من صنف آخر الخصائص والتّوابع المتواجدة به دون تعريفها من جديد، مما يسمح بالتركيز على الخصائص والتّوابع التي يتميز بها الصّنف الجديد.

وتستخدم الكلمة extends لتطبيق مفهوم الوراثة:

class Shape{
  protected int width;
  protected int height;

  public void setWidth(int a){
    width = a;
  }

  public void setHeight(int b){
    height = b;
  }
}

إذا كان لدينا هذا الصّنف وهو يُمثل شكلًا عامًا له طول وعرض وأردنا أن ننشئ شكلًا آخر (مربع) يرث من هذا الصّنف ويضيف خصائص أكثر:

class Square extends Shape{
  public int getArea(){
    return width * height;
  }
}

وبذلك أصبح Square يحتوي على الدالتين setWidth و setHeight بالإضافة للدالة الجديدة التي قام بتعريفها getArea، وبذلك استطعنا أن نعطي المزيد من الخصائص للشكل الجديد.

وإذا أردنا أن نصنع شكلًا آخر (مثلث):

class Triangle extends Shape{
  public int getArea(){
    return 0.5*width * height;
  }
}

لا يمكن للصّنف أن يرث من أكثر من أب.

وبتطبيق هذا المفهوم على الدرس السابق نجد أن أندرويد يحتوي على صنف اسمه View وهو الأب لكل العناصر الخاصة بواجهة المستخدم ويحدد الخصائص الأساسية والمشتركة بينهم جميعًا ويرث منه العناصر الخاصة مثل TextView وهو View ولكن يعرض نصًا فقط أو Button وأيًضا View قابل للضغط ويقوم بمهمة محددة عند الضغط عليه.

وإذا قمنا بالتعديل على المثال السابق واستخدمنا في Shape تابع البناء لتعريف الطول والعرض:

class Shape{
  protected int width;
  protected int height;

  public Shape(int a ,int b){
    width = a;
    height = b;
  }
}

ينبغي علينا أن نعرف دالة بناء للصّنف التي ترث منه:

class Square extends Shape{
  public Shape(int w ,int h){
    super(w,h);
  }

  public int getArea(){
    return width * height;
  }
}

وتستخدم super لاستدعاء Constructor الخاص بالأب وتمرير له القيم التي يحتاجها، وذلك لأن عند إنشاء كائن من Square والذي يرث من Shape:

Sqaure s = new Square(10,10);

يتم بناء الأب أولًا Shape ثم الابن Square حتى يكتمل بناء الكائن s بشكل صحيح.

لذا يتم تمرير في دالة البناء الخاصة بالابن ما تحتاجه دالة البناء الخاصة بالأب، ولم نقوم بذلك قبل التعديل لأننا كنا نستعمل دالة بناء فارغة في الأب.

التحويل من نوع بيانات إلى آخر

تمكننا لغات البرمجة من التحويل من نوع بيانات إلى آخر باستخدام مفهوم Casting، فمثلًا إذا كان لدينا متغير من النوع double:

double d = 12.5478;

ونريد تحويله إلى رقم صحيح:

int x = (int) d;

نفعل ذلك عن طريق كتابة نوع المتغير بين القوسين وبعدها اسم المتغير الذي نريد تحويله كما في المثال.

وهناك بعض الشروط على التحويل بين الأنواع بهذه الطريقة فلا يمكن تحويل String إلى int مثلًا لاختلاف النوعين عن بعضهما.

ويمكن تحويل من صنف إلى آخر شريطة أن يكون بينهما علاقة الوراثة.

Shape sh = new Shape(15,15);
Square s = (Square) sh;

بهذا نكون قد وصلنا إلى نهاية هذا الدّرس، في انتظار تجربتكم وآرائكم.

إن كانت لديك أيّة أسئلة فلا تتردّد في طرحها.


تفاعل الأعضاء

أفضل التعليقات

شكرًا لك. 

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

رابط هذا التعليق
شارك على الشبكات الإجتماعية

شكرا . لكنك يا صديقي قصرت في شرح الأخير (التغيير بين أنواع الكائنات). هل يمكنك أن تتعمق قليلا أو تدلني على رابط كتاب أو درس بالعربية ..

تم التعديل في بواسطة ايوب المبروكي
رابط هذا التعليق
شارك على الشبكات الإجتماعية

شكرا لك على شرحكم الممتع 

من فضلك محتاج مساعدة 

عندي كود من نوع post وهو مصفوفة تحتوي على بعض البيانات كما وضحت حضرتك أعلى وهذا الكلاس مخزن بياناته داخل adapter  استدعيت دالة حفظ البيانات getSharedPreferences وخزنتها في متغير ya ومعروف أن بيانتها من نوع string قمت بتخزين قيمتها في متغير بالشكل التالي 

String da = ya.getString("main","no data");

عند تخزينها في المصفوفة لعرضها عند فتح البرنامج في دالة onstart بالشكل التالي 

@Override protected void onStart() { super.onStart(); String da = ya.getString("main","no data"); listadapter.additem(da,""); }

يعطي خطأ بأنه لا يمكن تخزن da  في listadapter لأنها تحتاج نوع post 

ما الطريقة الصحيحة لتحويل البيانات من النوع String إلى post او ما الحل الصحيح لهذه العملية 

شكراً مقدماً

رابط هذا التعليق
شارك على الشبكات الإجتماعية

بتاريخ On 8/12/2020 at 15:48 قال Elord Yehia:

شكرا لك على شرحكم الممتع 

من فضلك محتاج مساعدة 

عندي كود من نوع post وهو مصفوفة تحتوي على بعض البيانات كما وضحت حضرتك أعلى وهذا الكلاس مخزن بياناته داخل adapter  استدعيت دالة حفظ البيانات getSharedPreferences وخزنتها في متغير ya ومعروف أن بيانتها من نوع string قمت بتخزين قيمتها في متغير بالشكل التالي 

String da = ya.getString("main","no data");

عند تخزينها في المصفوفة لعرضها عند فتح البرنامج في دالة onstart بالشكل التالي 

@Override protected void onStart() { super.onStart(); String da = ya.getString("main","no data"); listadapter.additem(da,""); }

يعطي خطأ بأنه لا يمكن تخزن da  في listadapter لأنها تحتاج نوع post 

ما الطريقة الصحيحة لتحويل البيانات من النوع String إلى post او ما الحل الصحيح لهذه العملية 

شكراً مقدماً

مرحبا يحيى،

هل يمكنك مشاركة الشيفرة البرمجية كامة، يمكنك وضع الكود مع تنسيقه في التعليق (كما يظهر في الجزء العلوي على اليمين). او إرفقاق الملفات.

في حال توزع البرنامج على عدة ملفات، أرجو إرفاق المجلد main مضغوطا ليتسنى مساعدتك بشكل أفضل.

 

تعديل:

على فرض أنك قمت بتعريف الصف بالطريقة التالية:

ListAdapter{
    void addItem(Post p);
}

كما قمت ب :

listadapter.addItem(String, String)

وأنت ذكرت أنه من النوع Post فالحل يكون:

listadapter.addItem(new Post(string, ""));

أي تمرير غرض من النوع Post:

new Post(string, "")

بالتوفيق

رابط هذا التعليق
شارك على الشبكات الإجتماعية



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...