أهلاً! في الدروس السابقة، قمنا بالتعمق في المصفوفات واستعرضنا الأمثلة الشائعة للعمل مع المصفوفات. في هذا الدرس، سنلقي نظرة فاحصة على Java ArrayList. بشكل عام، المصفوفات مفيدة للغاية. وكما لاحظت بالفعل، يمكنك فعل الكثير معهم :) لكن المصفوفات بها عدد من أوجه القصور.
- حجم محدود. أنت بحاجة إلى معرفة عدد العناصر التي يجب أن تحتويها صفيفتك في وقت إنشائها. إذا قللت من تقديرك، فلن يكون لديك مساحة كافية. إذا بالغت في التقدير، ستبقى المصفوفة نصف فارغة، وهو أمر سيء أيضًا. بعد كل شيء، لا تزال تقوم بتخصيص ذاكرة أكثر مما هو ضروري.
- لا تحتوي المصفوفة على طرق لإضافة العناصر. يجب عليك دائمًا الإشارة بوضوح إلى فهرس الموضع الذي تريد إضافة عنصر فيه. إذا قمت عن طريق الخطأ بتحديد فهرس لمركز يشغله بعض القيمة التي تحتاجها، فسيتم استبداله.
- لا توجد طرق لحذف عنصر. لا يمكن "تصفية" القيمة إلا.
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");
cats[1] = null;
System.out.println(Arrays.toString(cats));
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
الإخراج: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] لحسن الحظ، يدرك منشئو Java جيدًا مزايا وعيوب المصفوفات، وبالتالي أنشأوا بنية بيانات مثيرة جدًا للاهتمام تسمى Java ArrayList . إذا تحدثنا ببساطة قدر الإمكان، فإن Java ArrayList عبارة عن مصفوفة "مُحسَّنة" تحتوي على الكثير من الميزات الجديدة.
كيفية إنشاء قائمة ArrayList
من السهل جدًا إنشاء:ArrayList<Cat> cats = new ArrayList<Cat>();
لقد قمنا الآن بإنشاء قائمة لتخزين كائنات Cat . لاحظ أننا لا نحدد حجم ArrayList ، لأنه يمكن أن يتوسع تلقائيًا. كيف يكون هذا ممكنا؟ انها بسيطة جدا، في الواقع. قد يفاجئك ذلك، لكن ArrayList في Java مبني على مصفوفة عادية جدًا :) نعم، يحتوي على مصفوفة، حيث يتم تخزين العناصر لدينا. لكن ArrayList في Java لديه طريقة خاصة للعمل مع تلك المصفوفة:
- عند امتلاء المصفوفة الداخلية، تقوم ArrayList بإنشاء مصفوفة جديدة داخليًا. حجم المصفوفة الجديدة هو حجم المصفوفة القديمة مضروبة في 1.5 زائد 1.
- يتم نسخ جميع البيانات من المصفوفة القديمة إلى المصفوفة الجديدة
- يتم تنظيف المصفوفة القديمة بواسطة جامع البيانات المهملة.
add()
الطريقة
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat("Behemoth"));
}
تتم إضافة عناصر جديدة إلى نهاية القائمة. الآن ليس هناك أي خطر في تجاوز المصفوفة، لذا فإن هذه الطريقة آمنة تمامًا. بالمناسبة، لا يستطيع ArrayList العثور على كائن من خلال فهرسه فقط، ولكن أيضًا العكس: يمكنه استخدام مرجع للعثور على فهرس كائن في ArrayList ! هذا هو الغرض من طريقة IndexOf() : نقوم بتمرير مرجع إلى الكائن الذي نريده، ويقوم مؤشر IndexOf() بإرجاع فهرسه:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
int thomasIndex = cats.indexOf(thomas);
System.out.println(thomasIndex);
}
الإخراج: 0 هذا صحيح. تم بالفعل تخزين كائن توماس الخاص بنا في العنصر 0. المصفوفات ليس لها عيوب فقط. لديهم أيضا مزايا لا جدال فيها. إحداها هي القدرة على البحث عن العناصر حسب الفهرس. نظرًا لأننا نشير إلى فهرس، أي إلى عنوان ذاكرة محدد، فإن البحث في مصفوفة بهذه الطريقة يكون سريعًا جدًا. ArrayList
يعرف كيف يفعل ذلك أيضاً! تقوم طريقة get() بتنفيذ هذا:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
Cat secondCat = cats.get(1);
System.out.println(secondCat);
}
الإخراج: Cat{name='Behemoth'} بالإضافة إلى ذلك، يمكنك بسهولة معرفة ما إذا كانت قائمة ArrayList تحتوي على كائن معين. ويتم ذلك باستخدام طريقة ArrayList التي تحتوي على () :
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
cats.remove(fluffy);
System.out.println(cats.contains(fluffy));
}
تتحقق الطريقة مما إذا كانت المصفوفة الداخلية لـ ArrayList تحتوي على العنصر، وتقوم بإرجاع قيمة منطقية (صواب أو خطأ). الإخراج: خطأ وشيء آخر مهم حول الإدراج. يتيح لك ArrayList استخدام فهرس لإدراج العناصر ليس فقط في نهاية المصفوفة، ولكن في أي مكان. وله طريقتان لذلك:
- إضافة ArrayList (مؤشر int، عنصر Cat)
- مجموعة ArrayList (مؤشر int، عنصر Cat)
هنا مثال:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
System.out.println(cats.toString());
cats.set(0, lionel);// Now we have a list of 2 cats. Adding a 3rd using set
System.out.println(cats.toString());
}
الإخراج: [[Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Behemoth'}] كان لدينا قائمة بقطتين . ثم قمنا بإدراج عنصر آخر كعنصر 0 باستخدام طريقة set() . ونتيجة لذلك، تم استبدال العنصر القديم بعنصر جديد.
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
System.out.println(cats.toString());
cats.add(0, lionel);// Now we have a list of 2 cats. Adding a 3rd using add
System.out.println(cats.toString());
}
وهنا نرى أن add() يعمل بشكل مختلف. يقوم بتحريك جميع العناصر إلى اليمين ثم يكتب القيمة الجديدة كعنصر 0. الإخراج: [Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Thomas'}, Cat{name='Behemoth'}] لمسح القائمة بالكامل، نستخدم طريقة Clear() :
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
cats.clear();
System.out.println(cats.toString());
}
الإخراج: [] تمت إزالة كل شيء من القائمة. بالمناسبة، يرجى ملاحظة: على عكس المصفوفات، يتجاوز ArrayList طريقة toString() ويعرض القائمة بالفعل بشكل مناسب كسلاسل. مع المصفوفات العادية، كان علينا استخدام فئة المصفوفات لهذا الغرض. وبما أنني ذكرت المصفوفات : تتيح لك Java "التبديل" بسهولة بين المصفوفة وقائمة ArrayList ، أي تحويل واحدة إلى أخرى. تحتوي فئة Arrays على طريقة Arrays.asList() لهذا الغرض. نستخدمها للحصول على المحتويات كمصفوفة وتمريرها إلى مُنشئ ArrayList الخاص بنا :
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
Cat[] catsArray = {thomas, behemoth, lionel, fluffy};
ArrayList<Cat> catsList = new ArrayList<>(Arrays.asList(catsArray));
System.out.println(catsList);
}
الإخراج: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] يمكنك أيضًا الذهاب في الاتجاه المعاكس: get صفيف من كائن ArrayList . نقوم بذلك باستخدام طريقة toArray() :
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
Cat[] catsArray = cats.toArray(new Cat[0]);
System.out.println(Arrays.toString(catsArray));
}
ملاحظة: قمنا بتمرير مصفوفة فارغة إلى التابع toArray() . هذا ليس خطا. داخل فئة ArrayList ، يتم تنفيذ هذه الطريقة بحيث يؤدي تمرير مصفوفة فارغة إلى زيادة أدائها. فقط ضع ذلك في الاعتبار للمستقبل (بالطبع، يمكنك تمرير مصفوفة ذات حجم معين؛ وهذا سيعمل أيضًا). أوه، حول الحجم. يمكن العثور على الحجم الحالي للقائمة باستخدام طريقة size() :
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.size());
}
من المهم أن نفهم أنه على عكس خاصية طول المصفوفة ، فإن الأسلوب ArrayList.size() يُرجع العدد الفعلي للعناصر، وليس السعة الأصلية. بعد كل شيء، لم نحدد الحجم عند إنشاء ArrayList . ومع ذلك، يمكنك تحديده — يحتوي ArrayList على مُنشئ مناسب. لكن فيما يتعلق بإضافة عناصر جديدة، فهذا لا يغير سلوكه:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>(2);// create an ArrayList with an initial capacity of 2
Cat thomas = new Cat("Thomas");
Cat behemoth = new Cat("Behemoth");
Cat lionel = new Cat("Lionel Messi");
Cat fluffy = new Cat ("Fluffy");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.size());
}
مخرجات وحدة التحكم: 4 لقد أنشأنا قائمة مكونة من عنصرين، ولكنها توسعت بهدوء عندما كنا في حاجة إليها. وهناك اعتبار آخر وهو أننا إذا أنشأنا قائمة صغيرة جدًا في البداية، فسوف يتعين علينا توسيعها كثيرًا، الأمر الذي سيستخدم بعض الموارد. بالكاد تطرقنا إلى عملية إزالة العناصر من قائمة ArrayList في هذا الدرس. بالطبع، هذا ليس لأنه غاب عن أذهاننا. لقد وضعنا هذا الموضوع في درس منفصل ستلتقي به لاحقًا :) لتعزيز ما تعلمته، نقترح عليك مشاهدة درس فيديو من دورة Java الخاصة بنا
GO TO FULL VERSION