أهلاً! لقد عملنا سابقًا في تدريبك على كائنات فردية (وأنواع بدائية). ولكن ماذا لو أردنا العمل مع مجموعة كاملة من الكائنات بدلاً من كائن واحد فقط؟ على سبيل المثال، لنفترض أننا نريد إنشاء قائمة بأعياد ميلاد جميع الموظفين في شركتنا. يجب أن تحتوي على 30 سلسلة منسقة على النحو التالي: "سارة هوفمان، 25 يناير" سنستفيد من بنية بيانات خاصة تسمى المصفوفة . إذا قارنا المصفوفة بكائن حقيقي، فهي تشبه إلى حد كبير قبو بنك به صناديق ودائع آمنة: تتكون المصفوفة أيضًا من "صناديق". يمكنك وضع شيء (عنصر) في كل مربع. للوصول إلى عنصر ما، عليك معرفة رقم الصندوق (الفهرس). هذه هي الطريقة التي يتم بها إنشاء المصفوفة:
يمثل كل سطر
public class Main {
public static void main(String[] args) {
String [] birthdays = new String[10];
}
}
هنا نقوم بإنشاء مصفوفة تحتوي على 10 عناصر. يمكنك ملاحظة بعض ميزات المصفوفة على الفور:
- يقوم بتخزين عناصر من نوع بيانات محدد جيدًا . إذا قمنا بإنشاء مصفوفة سلسلة، فلا يمكننا تخزين أي شيء آخر فيها. يتم تحديد نوع البيانات عند إنشاء المصفوفة . وهذا هو المكان الذي يختلف فيه عن صندوق الودائع الآمن (حيث يمكن للعميل تخزين ما يريده).
- ويجب تحديد حجمه عند إنشاء المصفوفة . ولا يمكنك الإشارة إليه لاحقًا أو تغيير حجمه بعد إنشاء المصفوفة .
String [] birthdays = new String[10];
String birthdays [] = new String[10];
إذا كنت تريد كتابة شيء ما في مصفوفة، فأنت بحاجة إلى تحديد فهرس المربع الذي سيتم كتابة القيمة فيه. يتم ترقيم المربعات الموجودة في المصفوفة بدءًا من 0. يعد العد بدءًا من الصفر ممارسة شائعة جدًا في البرمجة. كلما اعتدت عليه بشكل أسرع، كان ذلك أفضل :) هذا يعني أنه إذا كنت تريد وضع بعض القيمة في المربع الأول ، فعليك القيام بما يلي:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
}
}
يتم الآن تخزين عيد ميلاد جانا في الخلية الأولى من مجموعة أعياد ميلاد الموظفين لدينا: يمكنك إضافة قيم أخرى بطريقة مماثلة:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
}
}
لاحظ أننا أضفنا عيد ميلاد روزي إلى المربع الثامن (أنت لم تنسى لماذا المربع رقم 7 هو المربع الثامن، أليس كذلك؟) . يمكنك أن ترى أننا لم نملأ جميع الخلايا الأخرى. ليس علينا كتابة القيم في مصفوفة بالترتيب. لا يوجد مثل هذا الشرط. بالطبع، كتابة العناصر بالترتيب تجعل من الأسهل بكثير تتبع عدد المربعات الفارغة وعدد المربعات المشغولة، ويمنع وجود "ثقوب" في المصفوفة. إذا كنت ترغب في الحصول على محتويات أحد الصناديق، فأنت (تمامًا كما هو الحال مع صندوق الأمانات) تحتاج إلى معرفة رقمه. هذا هو كيفية القيام به:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
String rosieBirthday = birthdays[7];
System.out.println(rosieBirthday);
}
}
إخراج وحدة التحكم: روزي ميلز، 3 يناير لقد أنشأنا String
متغيرًا وأخبرنا المترجم: "ابحث عن المربع الذي يحتوي على الفهرس 7 في مصفوفة أعياد الميلاد ، وقم بتعيين القيمة الموجودة هناك للمتغير String
rosieBirthday " . وهذا بالضبط ما فعلته. عند التعامل مع المصفوفات، يمكننا بسهولة العثور على طولها باستخدام خاصية خاصة: length .
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[7] = "Rosie Mills, January 3";
int birthdaysLength = birthdays.length;
System.out.println(birthdaysLength);
}
}
مخرجات وحدة التحكم: 10 ملاحظة: length
تقوم الخاصية بتخزين حجم المصفوفة، وليس عدد المربعات الممتلئة. تخزن مصفوفتنا 3 قيم فقط، لكننا أشرنا إلى أن حجمها هو 10 عندما أنشأناها. وهذه هي بالضبط القيمة التي length
يُرجعها الحقل. لماذا قد يكون هذا مفيدًا؟ حسنًا، لنفترض أنك تريد عرض قائمة بجميع أعياد الميلاد (للتحقق من عدم نسيان أي شخص). يمكنك القيام بذلك في حلقة واحدة بسيطة:
public class Main {
public static void main(String[] args) {
String birthdays [] = new String[10];
birthdays[0] = "Jana Russell, March 12";
birthdays[1] = "Landon Chan, May 18";
birthdays[2] = "Jeremiah Leonard, July 12";
birthdays [3] = "Kenny Russo, September 7";
birthdays[4] = "Tommie Barnes, November 9";
birthdays [5] = "Roman Baranov, August 14";
birthdays [6] = "Chanice Andersen, April 1";
birthdays[7] = "Rosie Mills, January 3";
birthdays [8] = "Keenan West, October 19";
birthdays [9] = "Abraham McArthur, May 3";
for (int i = 0; i < birthdays.length; i++) {
System.out.println(birthdays[i]);
}
}
}
في الحلقة، نعلن عن المتغير i
الذي تمت تهيئته إلى الصفر. في كل تمريرة، نحصل على العنصر ذو الفهرس i من مصفوفتنا ونعرض قيمته. ستقوم الحلقة بـ 10 تكرارات، وسوف أزيد من 0 إلى 9، والأرقام هي مؤشرات عناصر المصفوفة الخاصة بنا! ونتيجة لذلك، سوف نقوم بعرض كافة القيم من أعياد الميلاد[0] إلى أعياد الميلاد[9] في الواقع، هناك طريقة أخرى يمكنك من خلالها إنشاء مصفوفة. على سبيل المثال، يمكنك إنشاء مصفوفة من int
s مثل هذا:
public class Main {
public static void main(String[] args) {
int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
}
}
تسمى هذه التقنية "تهيئة الاختصار". إنه أمر مريح للغاية، لأننا نقوم في نفس الوقت بإنشاء مصفوفة وملئها بالقيم. ليس من الضروري أن نحدد حجم المصفوفة بشكل صريح: مع تهيئة الاختصار، length
يتم تعيين الحقل تلقائيًا.
public class Main {
public static void main(String[] args) {
int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
System.out.println(numbers.length);
}
}
مخرجات وحدة التحكم: 9 الآن، القليل عن كيفية تخزين المصفوفات في الذاكرة. لنفترض أن لدينا مجموعة من ثلاثة Cat
كائنات:
public class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public static void main(String[] args) {
Cat[] cats = new Cat[3];
cats[0] = new Cat("Thomas");
cats[1] = new Cat("Behemoth");
cats[2] = new Cat("Lionel Messi");
}
}
عليك أن تفهم بعض الأشياء هنا:
-
في حالة الأوليات، تقوم المصفوفة بتخزين مجموعة من القيم المحددة (على سبيل المثال
int
s). في حالة الكائنات، تقوم المصفوفة بتخزين مجموعة من المراجع .
يتكون المصفوفةcats
من ثلاثة عناصر، كل عنصر منها هو مرجع إلىCat
كائن. يشير كل مرجع إلى عنوان الذاكرة حيث يتم تخزين الكائن المقابل. - يتم ترتيب عناصر المصفوفة في كتلة واحدة في الذاكرة. يتم ذلك للسماح بالوصول إليها بسرعة وكفاءة.
cats
يشير إلى كتلة الذاكرة حيث يتم تخزين جميع الكائنات (عناصر المصفوفة). Cats[0]
يشير إلى عنوان محدد داخل هذه الكتلة. من المهم أن نفهم أن المصفوفة لا تقوم فقط بتخزين الكائنات: إنها كائن بحد ذاته. هذا يقودنا إلى التساؤل عما إذا كان بإمكاننا إنشاء ليس فقط مصفوفة من السلاسل أو الأرقام، ولكن أيضًا مصفوفات من المصفوفات . والجواب هو نعم نستطيع! يمكن للمصفوفة تخزين أي كائنات، بما في ذلك المصفوفات الأخرى. تسمى هذه المصفوفة ثنائية الأبعاد . إذا أردنا تمثيلها بصريًا، فستكون مشابهة جدًا لجدول عادي. لنفترض أننا نريد إنشاء مصفوفة مكونة من 3 مصفوفات يمكن لكل منها تخزين 10 int
ثوانٍ. انها تبدو مثل هذا:
int
مصفوفة. تحتوي المصفوفة الأولى على أرقام من 1 إلى 10، والمصفوفة الثانية - من -1 إلى -10، والثالثة - مجموعة من الأرقام العشوائية. يتم تخزين كل من هذه المصفوفات في صناديق المصفوفة ثنائية الأبعاد. في التعليمات البرمجية، تبدو تهيئة المصفوفة ثنائية الأبعاد كما يلي:
public static void main(String[] args) {
Cat[][] cats = new Cat[3][5];
}
تقوم قطط المصفوفة ثنائية الأبعاد الخاصة بنا بتخزين 3 مصفوفات مع 5 صناديق في كل مصفوفة. إذا أردنا وضع كائن في المربع الثالث من المصفوفة الثانية، فسنقوم بذلك:
public static void main(String[] args) {
Cat[][] cats = new Cat[3][5];
cats[1][2] = new Cat("Fluffy");
}
[1]
يشير إلى المصفوفة الثانية، [2]
ويشير إلى المربع الثالث من تلك المصفوفة. نظرًا لأن المصفوفة ثنائية الأبعاد تتكون من عدة مصفوفات، فمن أجل التكرار من خلالها وعرض جميع قيمها (أو ملء جميع عناصرها)، نحتاج إلى حلقة متداخلة:
for (int i = 0; i < cats.length; i++) {
for (int j = 0; j < cats[i].length; j++) {
System.out.println(cats[i][j]);
}
}
في الحلقة الخارجية (المتغيرة i
)، نقوم بالتكرار على جميع المصفوفات الموجودة في المصفوفة ثنائية الأبعاد. في الحلقة الداخلية (المتغيرة j
)، نمر عبر جميع عناصر كل مصفوفة. ونتيجة لذلك، سيتم عرض القطط[0][0] (المصفوفة الأولى، العنصر الأول) أولاً، تليها القطط[0][1] (المصفوفة الأولى، العنصر الثاني). بعد الانتهاء من المصفوفة الأولى، سنعرض القطط[1][0] ، القطط[1][1] ، القطط[1][2] ، وما إلى ذلك. بالمناسبة، تدعم المصفوفات ثنائية الأبعاد أيضًا التهيئة المختصرة:
int[][] numbers = {{1,2,3}, {4,5,6}, {7,8,9}};
عادةً، نعلن عن المصفوفة ثنائية الأبعاد numbers
على أنها مصفوفة int[3][3]
، لكن هذا الاختصار يتيح لنا تحديد القيم على الفور. لماذا تحتاج إلى مجموعة ثنائية الأبعاد؟ حسنًا، يمكنك استخدام واحدة لإعادة إنشاء لعبة "Battleship" الشهيرة بسهولة: في "Battleship"، يمكن وصف هيكل ساحة اللعب بسهولة: مصفوفة ثنائية الأبعاد مكونة من 10 مصفوفات تحتوي كل منها على 10 عناصر. يمكنك إنشاء اثنتين من هذه المصفوفات (واحدة لك وواحدة لخصمك)
int[][] battleshipBoard1 = new int[10][10];
int[][] battleshipBoard2 = new int[10][10];
استخدم بعض القيم (مثل الأرقام أو الرموز) لملء العناصر المقابلة لموقع سفنك، ثم قم بالتناوب في استدعاء الإحداثيات لعناصر محددة:
- سفينة حربيةBoard1[0][2]!
- يفتقد! سفينة حربيةBoard2[2][4]!
- يضرب!
- سفينة حربيةBoard2[2][5]!
- يضرب!
- سفينة حربيةBoard2[2][6]!,
- غرقت!
GO TO FULL VERSION