JavaRush /مدونة جافا /Random-AR /تحليل مفصل لفئة ArrayList [الجزء الأول]
Vonorim
مستوى

تحليل مفصل لفئة ArrayList [الجزء الأول]

نشرت في المجموعة
ستلقي هذه المقالة نظرة تفصيلية على فئة ArrayList من Collections Framework، والتي ربما تكون الأسهل في الفهم، نظرًا لأنها تعتمد على مصفوفة عادية. من المؤكد أنه سيتم طرح سؤال حول هذا الفصل وتطبيقه في Java أثناء المقابلة. في الجزء الثاني سنقوم بتحليل الطرق المتبقية وكتابة تطبيقنا الخاص لمصفوفة ديناميكية للأرقام. ترث فئة ArrayList من فئة AbstractList وتنفذ الواجهات التالية: List، RandomAccess، Cloneable، Serializable. تحليل مفصل لفئة ArrayList [الجزء 2] تحليل مفصل لفئة ArrayList [الجزء 1] - 1 تدعم فئة ArrayList المصفوفات الديناميكية التي يمكن توسيعها حسب الحاجة. يتم تفسير ضرورتها وفعاليتها من خلال حقيقة أن المصفوفة العادية لها طول ثابت: بمجرد إنشائها، لا يمكن أن تنمو أو تتقلص، مما يفرض قيودًا إذا لم يكن من المعروف حجم المصفوفة المطلوبة. في الأساس، فئة ArrayList عبارة عن صفيف قائمة متغيرة الطول لمراجع الكائنات. من المهم أن نفهم أن حجم (عدد الخلايا) للمصفوفة الداخلية لا يتناقص تلقائيًا عند إزالة العناصر منه. في الواقع، انخفضت قيمة المتغير size، الذي يشير إلى عدد العناصر الموجودة بالفعل في المصفوفة. لنفترض أننا أنشأنا كائنًا جديدًا من فئة ArrayList وأضفنا 5 عناصر إليه. بشكل افتراضي، يتم إنشاء مصفوفة مكونة من 10 عناصر. في هذه الحالة، ما يسمى بالسعة (الحجم/الحجم) للجسم ستكون تساوي 10، لكن قيمة المتغير sizeستكون تساوي خمسة. وعندما نقوم بحذف العناصر، نرى تغيرات في قيمة المتغير size، حيث .lengthلا يمكننا الوصول إلى المصفوفة الداخلية لفئة ArrayList ومعرفة طولها. يمكن تقليل الحجم باستخدام طريقة إضافية trimToSize()، والتي سيتم مناقشتها أدناه. دعونا نلقي نظرة على حقول الفصل.
  • الحقل المسؤول عن الحجم الافتراضي للمصفوفة الديناميكية:

    private static final int DEFAULT_CAPACITY = 10

    عند إنشاء كائن جديد، ArrayList<>() الجديد (منشئ بدون معلمات)، يتم إنشاء مصفوفة من 10 عناصر بالداخل.

  • الحقل الذي يتم فيه تخزين جميع عناصر المجموعة:

    transient Object[] elementData

    تم وضع علامة عليه بكلمة أساسية transient- لا تتم كتابة الحقل في دفق البايت عند استخدام خوارزمية التسلسل القياسية. تجدر الإشارة إلى أن الحقل لم يتم وضع علامة عليه بالكلمة الأساسية private، ولكن تم ذلك لتسهيل الوصول إلى هذا الحقل من الفئات المتداخلة (على سبيل المثال، القائمة الفرعية).

  • حقل عداد يخزن عدد العناصر الموجودة فعليًا في المصفوفة:

    private int size

    تتم زيادة/إنقاص القيمة عند إجراء عمليات مثل الإدراج والحذف.

هناك 3 حقول أخرى في الفصل الدراسي، لكنها في الأساس إضافية، لذلك لا فائدة من النظر فيها. يحتوي الفصل على ثلاثة منشئين:
  1. public ArrayList()- إنشاء مصفوفة قائمة فارغة مكونة من 10 عناصر؛
  2. public ArrayList(Collection < ? extends E > c)- إنشاء مصفوفة قائمة تمت تهيئتها بعناصر من المجموعة التي تم تمريرها (إذا أردنا إنشاء قائمة ArrayList جديدة بناءً على بعض المجموعات)؛
  3. public ArrayList(int initialCapacity)- إنشاء مصفوفة قائمة بسعة أولية. إذا كانت المعلمة الأولية التي تم تمريرها أكبر من 0، فسيتم إنشاء مصفوفة بالحجم المحدد (يتم تعيين ارتباط للحقل الداخلي elementData لمصفوفة جديدة من النوع كائن بالحجم الأولي). إذا كانت المعلمة 0، فسيتم إنشاء مصفوفة فارغة. إذا كانت المعلمة المحددة أقل من 0، فسيتم طرح IllegalArgumentException.
إنشاء كائن
List < String> list = new ArrayList<>();
يحتوي الكائن الذي تم إنشاؤه حديثًا listعلى خصائص (حقول) elementDataو size. مخزن القيمة elementDataليس أكثر من مصفوفة من نوع معين (محدد في عام - <>)، في حالتنا String[]. إذا تم استدعاء مُنشئ بدون معلمات، فسيتم إنشاء مصفوفة مكونة من 10 عناصر من النوع Object (مع التحويل إلى النوع بالطبع). تحليل مفصل لفئة ArrayList [الجزء 1] - 2إضافة عناصر تتم إضافة العناصر بشكل كلاسيكي إلى مصفوفة القائمة باستخدام المتغيرات المحملة بشكل زائد من ملف add().
public boolean add(E элемент)
حسنًا، دعنا نضيف: داخل هذه الطريقة، يتم استدعاء list.add("0"); تحليل مفصل لفئة ArrayList [الجزء 1] - 3نسخة مثقلة من الطريقة ، والتي تم وضع علامة عليها كـ ، والتي بدورها تأخذ ثلاث معلمات كمدخلات: العنصر المراد إضافته، والمصفوفة الداخلية وحجمها. في الطريقة الخاصة، يتم إجراء فحص: إذا كانت معلمة الحجم التي تم تمريرها تساوي طول المصفوفة الداخلية (أي أن المصفوفة ممتلئة)، فسيتم تعيين نتيجة الطريقة للمصفوفة (القيمة الحالية للحقل يتم تمرير size + 1 إلى الطريقة، لأنه من الضروري مراعاة العنصر الذي تتم إضافته)، حيث يتم تعيين رابط للمصفوفة الداخلية للمصفوفة الجديدة التي تم إنشاؤها عن طريق نسخ عناصر المصفوفة الأصلية: add()privategrow(int minCapacity)
Arrays.copyOf(elementData, newCapacity(minCapacity))
كمعلمة ثانية للطريقة، copyOfنشير إلى نتيجة الطريقة newCapacity(int minCapacity)، والتي يتم من خلالها حساب حجم المصفوفة الجديد. يتم حسابه باستخدام الصيغة التالية: int newCapacity = oldCapacity + (oldCapacity >> 1) بالنسبة لمصفوفة ذات الحجم الافتراضي، سيكون ما يلي صحيحًا: >> 1- إزاحة البت إلى اليمين بمقدار واحد (عامل يعمل على تقليل الرقم إلى نصفه). في الأساس، هذا يعني القسمة على 2 أس 1. اتضح أننا نقسم 10 على 2 ونضيف 10. المجموع، السعة الجديدة للمصفوفة هي 15، ولكن بما أننا نضيف العنصر الحادي عشر، إذن 15 + 1 = 16. دعنا نعود إلى قائمتنا ونفترض أننا أضفنا بالفعل 10 عناصر إليها ونحاول إضافة 11. سيظهر الفحص عدم وجود مساحة في المصفوفة. وفقًا لذلك، يتم إنشاء واستدعاء مصفوفة جديدة Arrays.copyOfتستخدم طريقة النظام داخليًا System.arraycopy(). تحليل مفصل لفئة ArrayList [الجزء 1] - 4تحليل مفصل لفئة ArrayList [الجزء 1] - 5أو هنا مثال واضح من مقالة واحدة عن JavaRush: تحليل مفصل لفئة ArrayList [الجزء 1] - 6بعد كل هذه الفحوصات وزيادة حجم المصفوفة إذا لزم الأمر، ثم في الطريقة الخاصة تتم add()إضافة عنصر جديد إلى نهاية المصفوفة، ويتم sizeزيادة المعلمة الحالية بمقدار واحد . ستتم معالجة المصفوفة القديمة لاحقًا بواسطة أداة تجميع البيانات المهملة. هذه هي الطريقة التي تعمل بها المصفوفة الديناميكية: عندما نضيف عناصر، نتحقق مما إذا كان لا يزال هناك مساحة فيها. إذا كان هناك مساحة، فإننا ببساطة نضيف العنصر إلى نهاية المصفوفة. النهاية لا تعني الخلية الأخيرة في المصفوفة، بل الخلية التي تتوافق مع القيمة size. أضفنا العنصر الأول إلى المصفوفة، وتم وضعه في الخلية ذات الفهرس [0]. زادت قيمة الحقل sizeبمقدار واحد و = 1. نضيف العنصر التالي: نرى ذلك size = 1، وبالتالي نضع العنصر في الخلية التي تحتوي على الفهرس [1] وهكذا. توجد نسخة مثقلة من الطريقة بمعلمتين:
public void add(int index, E element)
يمكننا تحديد موضع (فهرس) الخلية التي نريد إضافة العنصر إليها. أولا، يتم التحقق من صحة قيمة الفهرس المحددة، حيث أن هناك احتمال أن يتم تحديد فهرس غير صحيح، مما سيشير إلى خلية لا يوجد بها شيء، أو ببساطة غير موجودة. التحقق من الفهارس: index > size || index < 0– إذا كان الفهرس المحدد أكبر من الحجم الحالي للمصفوفة أو كان أقل من 0، فسيتم طرح استثناء IndexOutOfBoundsException. ثم، إذا لزم الأمر، يتم زيادة حجم المصفوفة، على غرار المثال أعلاه. ربما سمعت أنه أثناء عمليات الإضافة/الإزالة في المصفوفة، يتم نقل شيء ما إلى مكان ما (إما إلى اليمين أو إلى اليسار). لذلك، يتم تنفيذ الإزاحة عن طريق نسخ المصفوفة: System.arraycopy(elementData, index, elementData, index + 1, s - index); سيتم إزاحة جميع العناصر الموجودة على يمين الفهرس المحدد موضعًا واحدًا إلى اليمين (الفهرس+1). وفقط بعد ذلك يتم إضافة عنصر جديد إلى المصفوفة الداخلية في الفهرس المحدد. نظرًا لأننا قمنا بإزاحة جزء من المصفوفة إلى اليمين بمقدار واحد (لم يتم إنشاء مصفوفة جديدة)، فستكون الخلية التي نحتاجها متاحة للكتابة. تم مسح الرابط إلى المصفوفة القديمة، وفي المستقبل سيتم الاستيلاء عليه من قبل جامع البيانات المهملة. الصق كلمة "maserati" في الخلية [3]، المشغولة بالفعل:
تحليل مفصل لفئة ArrayList [الجزء 1] - 7
وبالتالي، عندما يتم إدراج عنصر في الفهرس ولا توجد مسافات خالية في المصفوفة، System.arraycopy()فسيتم الاستدعاء مرتين: الأول grow()في الطريقة نفسها add(index, value)، مما سيؤثر بشكل واضح على سرعة عملية الإضافة بأكملها. ونتيجة لذلك، عندما يكون من الضروري كتابة عنصر آخر إلى المصفوفة الداخلية، ولكن لا توجد مساحة هناك، فهذا ما يحدث داخل ArrayList:
  • يتم إنشاء مصفوفة جديدة بحجم أكبر بمقدار 1.5 مرة من المصفوفة الأصلية، بالإضافة إلى عنصر واحد.
  • يتم نسخ كافة العناصر من المصفوفة القديمة إلى المصفوفة الجديدة
  • يتم تخزين المصفوفة الجديدة في المتغير الداخلي لكائن ArrayList، ويتم تعريف المصفوفة القديمة بأنها غير مرغوب فيها.
يمكن زيادة سعة الكائنات من نوع ArrayList يدويًا باستخدام الطريقة:
public void ensureCapacity(int minCapacity)
من خلال زيادة سعة المصفوفة مسبقًا، يمكنك تجنب إعادة تخصيص ذاكرة الوصول العشوائي (RAM) الإضافية لاحقًا. تعمل هذه الطريقة على زيادة حجم المصفوفة الداخلية لاستيعاب عدد العناصر التي تم تمريرها إليها minCapacity. الطريقة ensureCapacity()لا تؤثر على الحقل size، بل تؤثر على capacity(حجم) المصفوفة الداخلية. مرة أخرى أؤكد أن sizeكلاهما capacityشيئان مختلفان ومن المهم جدًا عدم الخلط بينهما! إذا كنت تريد تقليل حجم المصفوفة الأساسية التي تم إنشاء ArrayList منها إلى العدد الحالي من العناصر المخزنة بالفعل، فيجب عليك استدعاء trimToSize(). بعد إزالة العناصر من المجموعة، size()سيظهر عدد العناصر الموجودة بالفعل، capacityولن ينخفض! لنفترض أننا أدخلنا 100 عنصر، وحذفنا أول 50 عنصرًا، sizeستصبح تساوي 50، وبالتالي capacityستبقى 100. لتقليل و capacity، نحتاج إلى استخدام الطريقة trimToSize()، التي تضبط قدرتنا بالكامل على الحجم الحالي. كيف تناسب؟ انسخ المصفوفة الخاصة بنا بحيث لا توجد خلايا فارغة متبقية (طول المصفوفة الجديدة يساوي ببساطة حقل الحجم).
تحليل مفصل لفئة ArrayList [الجزء 1] - 8
يمكنك أيضًا إضافة عناصر إلى مجموعتنا باستخدام addAll.
public boolean addAll(Collection< ? extends E> c)
public boolean addAll(int index, Collection< ? extends E> collection);
يتيح لك الخيار الأول إضافة كافة العناصر من المجموعة المحددة في معلمة الطريقة (على سبيل المثال، ورقة أخرى) إلى المجموعة الأصلية (أدخل في النهاية) التي تم إجراء استدعاء الطريقة لها. يتم تحويل المجموعة التي تم تمريرها (يمكن أيضًا أن تكون مجموعة) إلى مصفوفة باستخدام التابع toArray(). وبطبيعة الحال، تتم عملية الإضافة أيضًا باستخدام النسخ. والثاني هو إضافة كافة العناصر collectionإلى القائمة، بدءاً من الفهرس index. في هذه الحالة، ستنتقل جميع العناصر إلى اليمين حسب عدد العناصر الموجودة في القائمة collection. إزالة العناصر أولاً، دعونا نلقي نظرة على الخيارات الكلاسيكية لإزالة العناصر من قائمة ArrayList.
public E remove(int index)
ينفذ الحذف حسب الفهرس وينقل جميع العناصر اللاحقة (بعد العنصر الموجود في الفهرس المحدد) إلى اليسار، وبالتالي إغلاق "الثقوب". كما تقوم أيضًا بإرجاع العنصر المحذوف (E)، والذي تم كتابته مسبقًا إلى متغير إضافي قبل الحذف، والذي حصلنا على قيمته نتيجة لاستدعاء الطريقة. لفهم ما هو E، سوف تحتاج إلى التعرف على ما يسمى بالأنواع العامة. تشير العلامة E إلى أن الطريقة تُرجع نوع البيانات الذي تم تحديده عند إنشاء كائن ArrayList (تذكر: List <String> listوفقًا لذلك، في هذه الحالة، سيتم "استبدال" E String). للحصول على فهم عام، أوصي بشدة أن تتعرف على الأنواع العامة. يتم التحقق من صحة الفهرس الذي تم إدخاله، ثم داخل الطريقة، لا يتم حذف العنصر بالكامل، ولكن يتم استدعاء الطريقة الخاصة fastRemove(Object[] es, int i)، حيث يحدث الحذف بالفعل. نقوم بتمرير المصفوفة والفهرس المحدد إلى الطريقة كمدخل. يتم نسخ العناصر باستخدام System.arraycopy()، ويتم تقليل حجم المصفوفة، ثم نقوم بتعيين قيمة فارغة للعنصر الأخير. تجدر الإشارة إلى أنه لم يتم إنشاء مصفوفة جديدة: System.arraycopy(es, i + 1, es, i, size - 1 - i); يتم نسخ الجزء الموجود على يمين الموضع ضمن الفهرس المحدد (i+1) إلى المصفوفة (المصفوفات) الأصلية، ويقع بدءًا من الموضع نفسه (ط) المكان الذي يقع فيه العنصر المراد حذفه. وهكذا، قمنا بالتحول إلى اليسار ومحو عنصرنا.
Подробный разбор класса ArrayList [Часть 1] - 9
دعنا نحاول إزالة العنصر الموجود في الفهرس 3 من المصفوفة أدناه:
Подробный разбор класса ArrayList [Часть 1] - 10
لنفكر في الإصدار الثاني من الطريقة:
public boolean remove(Object o)
تقوم الطريقة بإزالة العنصر الذي تم تمريره من القائمة o، أو بشكل أكثر دقة، الكائن الموجود في الرابط المحدد. في حالة وجود عنصر في القائمة، تتم إزالته ويتم نقل جميع العناصر إلى اليسار. إذا كان العنصر موجودًا في القائمة وتمت إزالته بنجاح، فسترجع الطريقة صحيحًا، وإلا فسترجع خطأ. على غرار خيار الحذف حسب الفهرس، تسمى الطريقة fastRemove(), حيث تحدث نفس الإجراءات بالضبط. الفرق هو أن الطريقة remove(Object o)تبحث أيضًا عن الكائن المطلوب من خلال طريقة equals()فئة الكائن. عند الإزالة حسب القيمة، تمر الحلقة عبر كافة عناصر القائمة حتى يتم العثور على تطابق. سيتم حذف العنصر الأول الذي تم العثور عليه فقط. دعونا نلخص: عند حذف عناصر من مصفوفة ديناميكية، لا توجد فجوات متبقية كما هو الحال في المصفوفة العادية (لن تكون الخلية المحذوفة فارغة). يتم إزاحة جميع العناصر اللاحقة (التي كانت على يمين الفهرس) موضعًا واحدًا إلى اليسار. هناك عدة طرق إضافية يمكن استخدامها لإزالة العناصر من القائمة بدرجات متفاوتة. دعونا ننظر إليهم لفترة وجيزة. تنظيف مجموعتنا:
public void clear()
تتكرر حلقة بسيطة forعبر جميع عناصر المصفوفة، مع تعيين قيمة خالية لكل عنصر. يمكنك إزالة تلك العناصر من مجموعتنا الموجودة في مجموعة منقولة أخرى مثل هذا:
public boolean removeAll(Collection< ?> c)
إذا كنت بحاجة إلى إزالة عدة عناصر، فربما لا ينبغي عليك القيام بذلك في حلقة مشروطة: يعد استخدام الطريقة أكثر ملاءمة وأمانًا removeAll(). يقبل مجموعة من العناصر التي سيتم إزالتها من القائمة. يجب أن تحتوي المجموعة على عناصر من نفس النوع الذي تخزنه القائمة المستهدفة. وإلا سيتم طرحه بعيدا ClassCastException. ستعود الطريقة صحيحة إذا تم تغيير القائمة نتيجة لاستدعاء الطريقة.
Подробный разбор класса ArrayList [Часть 1] - 11
إزالة العناصر التي لا تنتمي إلى المجموعة التي تم تمريرها:
public boolean retainAll(Collection< ?> c)
Подробный разбор класса ArrayList [Часть 1] - 12
لنفترض أن لدينا مجموعة:
List< String> listFirst = new ArrayList<>();
listFirst.add("White");
listFirst.add("Black");
listFirst.add("Red");
والثانية:
List< String> listSecond = new ArrayList<>();
listSecond.add("Green");
listSecond.add("Red");
listSecond.add("White");
ثم بعد listSecond.retainAll(listFirst)ذلك listSecondسيبقى:

"White"
"Red"
نظرًا لأنه تمت إزالة "الأخضر" وهو غير موجود في listFirst. ولكن بعد listSecond.removeAll(listFirst)ذلك listSecondسيبقى:

"Green"
Удалorсь все элементы, которые есть в listFirst.
عدم الانتماء إلى المجموعة التي تم تمريرها - يعني أنه إذا كانت هناك عناصر غير موجودة في المجموعة التي تم تمريرها، فأنت بحاجة إلى إزالتها من المجموعة الأولى (التي يتم تطبيق الطريقة عليها). تنتمي إلى المجموعة المنقولة - وعليه، إذا كان هناك عنصر في كل من المجموعتين الأولى والثانية (المنقولة)، فسيتم إتلاف النسخة المكررة من الأولى.
protected void removeRange(int fromIndex, int toIndex)
يزيل من القائمة جميع العناصر الموجودة بين فهرس البداية المحدد (شامل) وفهرس النهاية المحدد (غير شامل). تجدر الإشارة إلى أنه لا يمكن استدعاء الطريقة مباشرةً على كائن ArrayList. لاستخدامه تحتاج إلى أن ترث من AbstractList/ArrayList. يتم استخدام الطريقة أيضًا بواسطة طريقة أخرى (القائمة الفرعية، والتي سيتم مناقشتها لاحقًا).
public boolean removeIf(Predicate< ? super E> filter)
يزيل العناصر من مجموعة بناءً على مسند معين. المسند نفسه عبارة عن وظيفة/خوارزمية/شرط معين سيتم على أساسه إزالة عنصر واحد أو أكثر يتوافق مع شرط معين. Predicate- واجهة وظيفية (تحتوي على طريقة واحدة فقط، لذا يمكن استخدامها كـ lambda)، تعمل على مبدأ "تم استلام معلمة واحدة - إرجاع منطقية". في الأساس، تتجاوز الطريقة التنفيذ من الواجهة Collectionوتنفذ "الإستراتيجية" التالية: فهي تتكرر عبر العناصر وتضع علامة على العناصر التي تطابقنا Predicate؛ ثم يتم تشغيله مرة ثانية لإزالة (وتحويل) العناصر التي تم تمييزها في التكرار الأول. دعونا ننفذ واجهة Predicateتعود صحيحة إذا كان هناك كائنان متساويان:
class SamplePredicate< T> implements Predicate< T>{
  T varc1;
  public boolean test(T varc){
     if(varc1.equals(varc)){
       return true;
  }
  return false;
  }
}
في فئة أخرى، لنقم بإنشاء ArrayList من Stringوكائن من فئتنا يقوم بتنفيذ Predicate:
ArrayList< String> color_list = new ArrayList<> ();
SamplePredicate< String> filter = new SamplePredicate<> ();
varc1لنكتب القيمة "White" للمتغير :
filter.varc1 = "White";
دعنا نضيف بضعة أسطر إلى القائمة:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
لننفذ الطريقة الموجودة في القائمة removeIf، والتي سنمرر إليها الكائن مع الشرط:
color_list.removeIf(filter);
نتيجة لذلك، ستتم إزالة كافة الصفوف ذات القيمة "الأبيض" من القائمة، حيث أن "المسند" الخاص بنا يقارنها بالمساواة. القائمة النهائية: [أسود، أحمر، أصفر].
Подробный разбор класса ArrayList [Часть 1] - 13
استبدال العناصر
public E set(int index, E element)
يستبدل العنصر الموجود في الموضع المحدد indexبالعنصر الذي تم تمريره element. يجب أن يكون الفهرس أيضًا أكبر من الصفر وأقل من فهرس العنصر الأخير، وإلا فسيتم طرح استثناء IndexOutOfBoundsException. لا توجد نسخ من الصفيف الداخلي. ببساطة، بدلاً من العنصر الموجود في الفهرس المحدد، يتم إدراج عنصر جديد، أي. الكتابة فوق القيمة.
Подробный разбор класса ArrayList [Часть 1] - 14
public void replaceAll(UnaryOperator<e> operator)
يغير جميع عناصر المجموعة (ممكن بشرط). يُستخدم غالبًا مع لامدا أو فئة مجهولة (ولكن من أجل الوضوح، في المثال سنستخدم ببساطة فئة تنفذ الواجهة) تنفذ الواجهة UnaryOperatorوتحدد أساليبها. لننفذ الواجهة:
class MyOperator< T> implements UnaryOperator< T>{
   T varc1;
   public T apply(T varc){
     return varc1;
  }
}
في فئة أخرى، لنقم بإنشاء ArrayList من Stringوكائن من فئتنا يقوم بتنفيذ UnaryOperator:
ArrayList< String> color_list = new ArrayList<> ();
MyOperator< String> operator = new MyOperator<> ();
varc1لنكتب القيمة "White" للمتغير :
operator.varc1 = "White";
دعنا نضيف بضعة أسطر إلى القائمة:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
لننفذ طريقة في القائمة replaceAllسنمرر إليها كائننا operator:
color_list.replaceAll(operator);
ونتيجة لذلك، تم استبدال كافة القيم في القائمة بـ "أبيض": [أبيض، أبيض، أبيض، أبيض، أبيض، أبيض]. وهذه هي الطريقة، على سبيل المثال، يمكنك إزالة كافة المسافات من السلاسل الموجودة في المجموعة:
ArrayList< String> list = new ArrayList<>(Arrays.asList("A   ", "  B  ", "C"));
list.replaceAll(String::trim);
طرق أخرى: يمكنك تحويل مصفوفة قائمة ArrayList إلى مصفوفة عادية باستخدام الطريقة:
public Object[] toArray()
أو
public < T> T[] toArray(T[] a)
- هنا يتم تحديد نوع المصفوفة التي تم إرجاعها بهذه runtime الطريقة ستسمح بما يلي:
  1. تسريع بعض العمليات.
  2. تمرير مصفوفة كمعلمة إلى طريقة غير مثقلة لقبول المجموعة مباشرة؛
  3. دمج التعليمات البرمجية الجديدة المستندة إلى المجموعة مع التعليمات البرمجية القديمة التي لا تتعرف على المجموعات.
إرجاع كائن نسخة من المصفوفة:
public Object clone()
يرجى ملاحظة أن الطريقة clone()تُرجع نوع الكائن، لذا بعد استدعائها ستحتاج إلى الإرسال إلى الفئة المطلوبة. يؤدي الاستنساخ إلى إنشاء كائن مستقل جديد. التحقق من المجموعة لوجود كائن:
public boolean contains(Object o)
التحقق من وجود كائن في القائمة (داخليًا باستخدام طريقة يساوي لفئة الكائن، أي مقارنة المراجع)، وإرجاع صحيح/خطأ اعتمادًا على النتيجة. بالإضافة إلى الحلقات المعتادة، يمكنك التكرار عبر مجموعة (الوصول إلى كل عنصر، وكذلك تنفيذ بعض الإجراءات) باستخدام:
public void forEach(Consumer< ? super E> action)
هذه هي الطريقة التي يمكننا بها عرض قائمتنا:
List< Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 50, 100, -5));
numbers.forEach((number)-> System.out.println(number));
بدون استخدام lambdas، يلزمك استخدام فئة مجهولة وتجاوز طريقة acceptالواجهة Consumer:
numbers.forEach(new Consumer< Integer>() {
  @Override
   public void accept(Integer integer) {
      System.out.println(integer);
          }
});
الحصول على عنصر حسب فهرسه:
public E get(int index)
تستخدم للوصول العشوائي إلى عناصر المجموعة. إرجاع العنصر الموجود في القائمة في الفهرس المحدد. إذا index < 0كان index >=الحد الأقصى لعدد العناصر في القائمة أو هو، فسيتم طرح استثناء IndexOutOfBoundsException. هذه هي الطريقة الأساسية لاسترداد عنصر من القائمة، وسيكون وقت استرداد العنصر حسب الفهرس هو نفسه دائمًا، بغض النظر عن حجم ArrayList، نظرًا لأنه يصل إلى خلية صفيف محددة. البحث عن فهارس لكائنات محددة:
public int indexOf(Object o);
public int lastIndexOf(Object o);
تقوم الطرق بإرجاع فهرس العنصر الأول (عند مواجهة الكائن المحدد لأول مرة) أو العنصر الأخير (عند مواجهة الكائن المحدد آخر مرة) في القائمة. إذا كان العنصر غير موجود في القائمة، فسوف ترجع الطرق -1.
Подробный разбор класса ArrayList [Часть 1] - 16
Подробный разбор класса ArrayList [Часть 1] - 17
التحقق من المجموعة للعناصر:
public boolean isEmpty();
تُرجع الطريقة صحيحًا إذا كانت القائمة فارغة (تبحث لمعرفة ما إذا كان الحقل يساوي size 0)، وإلا فستُرجع خطأ. إذا كانت القائمة تحتوي على عناصر فارغة فقط، فسترجع الطريقة خطأ. بمعنى آخر، يتم أيضًا أخذ العناصر الفارغة في الاعتبار بهذه الطريقة. معرفة عدد العناصر في القائمة:
public int size();
إرجاع عدد العناصر في القائمة (قيم حقل الحجم). قد يختلف عدد العناصر عن سعة القائمة (السعة). الحصول على مكرر لقائمة:
public Iterator< E> iterator();
إرجاع مُكرِّر لقائمة لاستخدامها لاحقًا في حلقة أو أي معالجة أخرى. ينفذ المكرر سلوكًا سريع الفشل. إذا تم تشغيله عبر المجموعة ولاحظ بعض التعديلات عليها (التي لم يتم الحصول عليها باستخدام أساليب التكرار)، فسيطرح استثناءً على الفور ConcurrentModificationException. المكرر لديه شيء يسمى modification count. عندما يقوم المكرِّر بالتكرار خلال المجموعة بعد كل مرة next/hasNext/remove، فإنه يتحقق من هذا العداد. إذا لم يتطابق مع ما توقع المكرِّر رؤيته، فسيطرح استثناءً. لن أفكر في التكرارات بالتفصيل هنا.
public ListIterator< E> listIterator() и public ListIterator< E> listIterator(int index)
تقوم بإرجاع مكرر القائمة لقائمة لاستخدامها لاحقًا في حلقة أو أي معالجة أخرى. تعمل الواجهة ListIteratorعلى توسيع الواجهة Iteratorللتنقل ثنائي الاتجاه للقائمة وتعديل عناصرها. في الإصدار المثقل، يمكنك تمرير الفهرس الذي سيبدأ منه "الاجتياز". يشير الفهرس في هذه الحالة إلى العنصر الأول الذي ستبدأ منه الطريقة عملها next()، وعندما يتم استدعاء الطريقة، previous()سيبدأ الاجتياز من العنصر الموجود تحت الفهرس "مؤشر تمرير - 1".
public Spliterator <E> spliterator()
يقدم Java 8 نوعًا جديدًا من مكرر الربط المتأخر وسريع الفشل يسمى مكرر المحدد. تسمح لك مكررات الفاصل بالتكرار على سلسلة من العناصر، ولكن يتم استخدامها بطريقة مختلفة. الميزة الأكثر أهمية في واجهة Spliterator هي قدرتها على دعم التكرار المتوازي للأجزاء الفردية لسلسلة من العناصر، وبالتالي البرمجة المتوازية.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION