مرحبًا! محاضرة اليوم
ArrayList
ستكون من ناحية أبسط، ومن ناحية أخرى أصعب من المحاضرات السابقة. الأمر أكثر صعوبة، لأننا سننظر اليوم "تحت الغطاء" ArrayList
وندرس ما يحدث له أثناء العمليات. من ناحية أخرى، لن يكون هناك أي كود تقريبًا في هذه المحاضرة - معظمها صور وشروحات. لذلك، دعنا نذهب :) كما تعلم بالفعل، ArrayList
يوجد داخل "a" مصفوفة عادية تعمل كمخزن بيانات. في معظم الحالات، لا نحدد الحجم الدقيق للقائمة. لكن المصفوفة الداخلية يجب أن يكون لها حجم معين! هذا صحيح. حجمه الافتراضي هو [10] .
public static void main(String[] args) {
ArrayList<Car> cars = new ArrayList<>();
}
أولاً، دعونا نلقي نظرة على الشكل الذي تبدو عليه إضافة عنصر جديد. أولاً، يتم إجراء فحص لمعرفة ما إذا كانت هناك مساحة كافية في المصفوفة الداخلية وما إذا كان هناك عنصر آخر مناسب أم لا. إذا كان هناك مساحة، تتم إضافة العنصر الجديد إلى نهاية القائمة. عندما نقول "إلى النهاية"، فإننا لا نعني الخلية الأخيرة من المصفوفة (سيكون ذلك غريبًا). يشير هذا إلى الخلية المجاورة للعنصر الحالي الأخير. فمؤشره سيكون مساوياً لـ cars.size()
. قائمتنا فارغة حاليا ( cars.size() = 0
). وبناء على ذلك، سيتم إضافة عنصر جديد إلى الخلية ذات الفهرس 0
.
ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
cars.add(ferrari);
كل شيء واضح هنا. ماذا سيحدث إذا تم الإدراج في المنتصف، أي بين عدة عناصر؟
public static void main(String[] args) {
ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
Car bugatti = new Car("Bugatti Veyron");
Car lambo = new Car("Lamborghini Diablo");
Car ford = new Car("Ford Modneo");
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
cars.add(1, ford);//добавляем ford в ячейку 1, которая уже занята
}
مرة أخرى، يقوم أولاً بالتحقق مما إذا كانت هناك مساحة كافية في المصفوفة. إذا كانت هناك مساحة كافية، يتم نقل العناصر إلى اليمين بدءًا من الخلية التي نقوم بإدراج العنصر الجديد فيها. نلصق في الخلية التي تحتوي على الفهرس 1. أي أنه يتم نسخ العنصر من الخلية 3 إلى الخلية 4، والعنصر 2 إلى الخلية 3، والعنصر 1 إلى الخلية 2. وبعد ذلك، يتم لصق العنصر الجديد في مكانه. bugatti
تم بالفعل نسخ العنصر السابق ( ) من هناك إلى موقع جديد. الآن دعونا نتعرف على كيفية حدوث هذه العملية إذا لم تكن هناك مساحة للإدراج في المصفوفة. أولاً، بالطبع، يتم إجراء فحص لمعرفة ما إذا كانت هناك مساحة كافية. إذا اتضح أنه لا توجد مساحة كافية، ArrayList
فسيتم إنشاء مصفوفة جديدة بالحجم (حجم OldArray * 1.5) + 1 داخل "a. في حالتنا، سيكون حجم المصفوفة الجديدة 16 خلية. سيتم نسخ كافة العناصر الحالية هناك على الفور. سيتم حذف المصفوفة القديمة بواسطة جامع البيانات المهملة، وسيبقى المصفوفة الجديدة الموسعة فقط. الآن هناك مساحة حرة للعنصر الجديد. نلصقه في الخلية رقم 3 المشغولة. الآن يبدأ الإجراء المألوف. يتم نقل كافة العناصر التي تبدأ من الفهرس 3 خلية واحدة إلى اليمين، ويتم إضافة عنصر جديد بهدوء. والآن تم الإدراج بنجاح! لقد قمنا بفرز الإدراج. الآن دعونا نتحدث عن إزالة العناصر . كما تتذكر، عند العمل مع المصفوفات، واجهنا مشكلة: عندما قمنا بحذفها، ظلت "الثقوب" فيها. كان الحل الوحيد هو نقل العناصر إلى اليسار في كل مرة يتم حذفها، وكان عليك كتابة رمز النقل بنفسك. ArrayList
يعمل على نفس المبدأ، ولكن يتم تنفيذ هذه الآلية فيه بالفعل تلقائيا. وهذا ما يبدو عليه الأمر: وفي النهاية حصلنا على النتيجة المرجوة: تم حذف العنصر lambo
بنجاح. هنا قمنا بالإزالة من المنتصف. ومن الواضح أن الحذف من نهاية القائمة سيكون أسرع، حيث تتم إزالة العنصر المطلوب دون تغيير جميع العناصر الأخرى. دعونا نلقي نظرة أخرى على حجم المصفوفة الداخلية وتخزينها في الذاكرة. توسيع المصفوفة هو عملية تتطلب قدرًا معينًا من الموارد. لذلك، لا ينبغي عليك الإنشاء ArrayList
بالحجم الافتراضي إذا كنت تعرف على وجه اليقين أنه سيحتوي على 100 عنصر على الأقل. بحلول الوقت الذي تقوم فيه بإدراج العنصر رقم 100، ستتوسع المصفوفة الداخلية 6 مرات ، مع نقل جميع العناصر في كل مرة.
- من 10 عناصر إلى 16
- من 16 عنصرًا إلى 25 عنصرًا
- من 25 إلى 38
- من 38 إلى 58
- من 58 إلى 88
- من 88 إلى 133 (حسب الصيغة (حجم المصفوفة القديمة * 1.5) + 1)
ArrayList<Car> cars = new ArrayList<>(100);
الآن سيتم تخصيص مجموعة من 100 عنصر على الفور في الذاكرة، والتي ستكون أكثر كفاءة لأنه لن يتم إهدار الموارد في التوسيع. وهناك أيضًا الوجه الآخر للعملة. عند إزالة الكائنات من ArrayList
المصفوفة الداخلية، لا يتم تقليل الحجم تلقائيًا. على سبيل المثال، لدينا ArrayList
مصفوفة داخلية مكونة من 88 عنصرًا، وهي مملوءة بالكامل: أثناء تشغيل البرنامج، نزيل منها 77 عنصرًا، ويبقى فيها 11 عنصرًا فقط: هل خمنت بالفعل ما هي المشكلة؟ الاستخدام غير الفعال للذاكرة، بطبيعة الحال! نحن نستخدم 11 خلية فقط، بينما لدينا ذاكرة مخصصة لـ 88 عنصرًا - وهذا أكثر بثمانية أضعاف مما نحتاجه! لتنفيذ التحسين في هذه الحالة، يمكنك استخدام طريقة فئة خاصة ArrayList
- trimToSize()
. إنه "يقطع" طول المصفوفة الداخلية إلى عدد العناصر المخزنة فيها حاليًا. الآن يتم تخصيص أكبر قدر من الذاكرة حسب الحاجة! :)
GO TO FULL VERSION