نظرة عامة على ArrayList:
يتم تنفيذ ArrayList استنادًا إلى المصفوفات وهو صفيف ديناميكي يمكن أن تنمو قدرته تلقائيًا ، على غرار ذاكرة التطبيق الديناميكية بلغة C ، مما يزيد من الذاكرة ديناميكيًا.
ArrayList ليس آمنًا للموضوع ولا يمكن استخدامه إلا في بيئة واحدة. في بيئة متعددة الخيوط ، يمكنك التفكير في استخدام الدالة SynchronizedList (LIST L) لإرجاع فئة ArrayList آمنة مؤشرات ترابط ، أو يمكنك استخدام فئة CopyOnWriteArrayList ضمن حزمة متزامنة متزامنة.
يقوم ArrayList بتنفيذ الواجهة التسلسلية ، لذلك يدعم التسلسل ، يمكن نقله من خلال التسلسل ، ويقوم بتنفيذ واجهة الوصول العشوائي ، ويدعم الوصول العشوائي السريع. في الواقع ، يتم الوصول السريع من خلال الرقم التسلسلي للتراجع ، ويقوم بتنفيذ الواجهة المستنسخة ، ويمكن استنساخه.
كل مثيل ArrayList له سعة ، تشير إلى حجم الصفيف المستخدم لتخزين عناصر القائمة. هو دائما على الأقل يساوي حجم القائمة. مع إضافة العناصر باستمرار إلى قائمة ArrayList ، تزداد قدرتها أيضًا تلقائيًا. سيؤدي النمو التلقائي إلى إعادة تصميم البيانات إلى الصفيف الجديد ، لذلك إذا تمكنت من التنبؤ بكمية البيانات ، فيمكنك تحديد قدرتها عند إنشاء قائمة ArrayList. قبل إضافة عدد كبير من العناصر ، يمكن للتطبيق أيضًا استخدام عملية EnsureCapacity لزيادة قدرة مثيل ArrayList ، والتي يمكن أن تقلل من عدد عمليات إعادة التوزيع الإضافية.
لاحظ أن هذا التنفيذ ليس متزامنًا. إذا وصلت مؤشرات الترابط المتعددة إلى مثيل ArrayList في نفس الوقت ، وعلى الأقل واحدة من مؤشرات الترابط تعديل القائمة بشكل هيكلي ، فيجب أن تظل متزامنة خارجيًا.
دعونا نحقق سجلًا وملخصًا لـ Java ArrayList
العناصر العامة ArrayList <E> { / *** العناصر التي تخزن المجموعة** / كائن عابر خاص [] ElementData ؛ / ** حجم العنصر*/ حجم int الخاص ؛حدد فئة عامة ومجموعة من الكائن ومتغير خاص لتسجيل عدد العناصر في المجموعة. هناك متغير خاص إضافي في النص الأصلي ، ولا أعرف ماذا يمكنني استخدامه ، وليس للمؤلف أي تفسير أو ذكره. لا بأس إذا لم أستخدمه.
/ ** * تهيئة وفقًا للحجم المحدد * param initialCapacity */ public arrayList (int initialCapacity) {super () ؛ if (initialCapacity <= 0) {// استثناء رمي جديد غير unalfalArgumentException ("لا يمكن أن تكون معلمة التهيئة أقل من 0") ؛ } آخر {// تهيئة الصفيف this.elementData = كائن جديد [initialCapacity] ؛ }} / *** التهيئة الافتراضية* / ArrayList () {this (10) ؛ } /*** تهيئة وفقًا لفئة تجميع* param c فئة يجب أن ترث واجهة التجميع* /ArrayList العامة (مجموعة <؟ تمديد E> C) {// تهيئة ElementData = C.Toarray () ؛ الحجم = elementData.Length ؛ // قم بتحويل نوع الكائن if (elementData.getClass ()! = Object [] }} 3 طرق التهيئة ، قم بتهيئة المصفوفة وفقًا للحجم الافتراضي ، وقم بتهيئة الحجم المحدد وتمرير فئة ترث واجهة جمع المجموعة لتهيئة مهمة التحويل
/ *** مجموعة التوسع* param mincapacity*/ public void insureCapacity (int mincapacity) {/ ** الحجم الحالي للمصفوعة*/ int oldcapacity = elementData.length ؛ إذا لم يتم استخدام (MinCapacity> OldCapacity) { /*** على الرغم من عدم استخدام OldData ، فإن هذا يتعلق بإدارة الذاكرة والصفائف. المواضيع من تخصيص ذاكرة Memory ElementData من التعدي عليها. * عندما تغادر النهاية إذا انتهت دورة OldData ويتم إعادة تدويرها*/ Object OldData [] = elementData ؛ int newCapacity = (OldCapacity * 3)/2 + 1 ؛ // زيادة 50 ٪+1 إذا (newCapacity <mincapacity) newCapacity = mincapacity ؛ // استخدم المصفوفات. }}هذه طريقة أساسية. يتم توسيع المجموعة في الواقع لمقارنة توسيع المصفوفة وحجم مجموعة MinCapacity لتحديد ما إذا كان ينبغي توسيعها. يتم استخدام طريقة Arrays.copyof () للتوسع.
النص الأصلي له تفسير مفصل. تقوم هذه الطريقة بنسخ محتوى المعلمة الأولى إلى صفيف جديد. حجم الصفيف هو المعلمة الثانية ويعيد صفيفًا جديدًا. هناك تعليقات مفصلة على متغيرات Olddata.
/ *** تحقق مما إذا كان الفهرس خارج الحدود* param index*/ private void rangecheck (int index) {if (index> size || index <0) {throw indexoutofboundsexception ("المؤشر يتجاوز ، الفهرس:" + index + "، الحجم:" + حجم) ؛ }}ما إذا كان البحث التراكمي هو 1 /**
* إضافة عنصر* أضف العنصر المحدد إلى نهاية المجموعة* param e العنصر المضافة* @return*/ public boolean add (e e) {insureCapacity (size+1) ؛ elementData [size] = e ؛ حجم ++ ؛ العودة صحيح. }أضف عنصرًا ، وتوسيع السعة أولاً ، وتعيين القيمة ، ثم أضف العنصر. لاحظ أنه لم يتم إضافة حجم الحقل+1. فيما يلي عملية حسابية ، لذلك من الضروري زيادتها لاحقًا.
/ *** إضافة عنصر* إضافة عنصر إلى الموضع المحدد* param INDEX المحدد عنصر فهرس الفهرس العنصر* param element* return*/ public boolean add (int index ، e element) {rangecheck (index) ؛ insureCapacity (حجم+1) ؛ // elementData element بدءًا من موضع الفهرس وطول الحجم ، // انسخ إلى صفيف ElementData جديد يبدأ من موضع الفهرس كفهرس+1. // هذا يعني أن العنصر الموجود حاليًا في هذا الموقف وجميع العناصر اللاحقة يتم نقله بشكل صحيح بموقع واحد. System.ArrayCopy (elementData ، index ، elementData ، index+1 ، size-index) ؛ elementData [index] = element ؛ Size ++ ؛ // إضافة عنصر واحد إرجاع صحيح ؛ }الفرق هنا هو System.arrayCopy (elementData ، index ، elementData ، index+1 ، size-index) ؛
هذه طريقة داخلية لـ C. النص الأصلي التفصيلي له شرح ، لذلك لن أتحدث عنه هنا. هذا هو أيضًا جوهر قائمة ArrayList بأكملها وأيضًا مبدأ التنفيذ الداخلي لـ Arrays.copyof ()
/*** أضف جميع العناصر* إضافة جميع العناصر في المجموعة إلى نهاية هذه القائمة بترتيب العناصر التي يتم إرجاعها بواسطة Iterator للمجموعة المحددة. * param c * return */ public boolean addall (مجموعة <؟ تمتد e> c) {object [] newElement = c.toarray () ؛ int elementLength = newElement.length ؛ insureCapacity (Size+ElementLength) ؛ // من مجموعة NewElement 0 ، ElementLength Elements ، Sizedata Size Subcript System.ArrayCopy (NewElement ، 0 ، ElementData ، Size ، ElementLength) ؛ الحجم+= ElementLength ؛ إرجاع ElementLength! = 0 ؛ }في الأساس ، تقوم الطرق الأخرى بمعالجة مختلفة فقط وفقًا للمواقف المختلفة ، مثل تمرير كائنات البيانات من خلال الواجهة والحصول على طول للتوسع ، ونسخ البيانات إلى صفيف جديد باستخدام النظام و arraycopy.
/ *** حدد الموقف ، أضف جميع العناصر* @Param Index Index INDEX* Param C Collection Enserted Elements* @Return*/ public boolean addall (int index ، collection <؟ extends e> c) {if (index> size || index <0) {thraw new indexoutofboundsexception ( } object [] newElement = C.Toarray () ؛ int elementLength = newElement.length ؛ insureCapacity (Size+ElementLength) ؛ int numMoved = Size-Index ؛ // الحكم على ما إذا كان موضع الإدراج في منتصف المصفوفة إذا (numroved> 0) {// انقل جميع العناصر وراء موضع إدخال الفهرس للخلف // إدراج العناصر nummoved بدءًا من فهرس فهرس الفهرس إلى فهرس+elementlength ، nummoved ، } // إضافة ElementLength في newElement من 0 إلى الموضع حيث يبدأ elementData Index System.arrayCopy (newElement ، 0 ، elementData ، index ، elementLength) ؛ الحجم += ElementLength ؛ إرجاع ElementLength! = 0 ؛ } / ** * حدد قيمة الفهرس * param index * param element * return * / public e set (int index ، e element) {rangecheck (index) ؛ e OldElement = (e) elementData [index] ؛ elementData [index] = element ؛ العودة القديمة. } / ** * احصل على القيمة استنادًا إلى الفهرس * param index * @return * / public e get (int index) {rangecheck (index) ؛ إرجاع (هـ) elementData [index] ؛ } / *** قم بإزالة العنصر وفقًا لـ subcript* param index* / public e remove (int index) {rangecheck (index) ؛ e OldElement = (e) elementData [index] ؛ / ** عدد العناصر بعد الانتشار الذي تم إزالته*/ int numMoved = size-index-1 ؛ // إذا تم نقله داخل نطاق المصفوفة إذا كان (numMoved> 0) system.arrayCopy (elementData ، index+1 ، elementData ، index ، numMoved) ؛ // إزالة elementData [-size] = null ؛ العودة القديمة. } /** * إزالة وفقًا للعنصر * param obj * return * /public boolean إزالة (كائن OBJ) {// arraylist يتيح NULL ، لذلك يجب أيضًا تنفيذ معالجة الحكم أيضًا إذا (ubj == null) {for (index index = 0 ؛ index <size ؛ index ++) {if (elementData [index] == null) العودة صحيح. }}} آخر {for (int index = 0 ؛ index <size ؛ index ++) {if (obj.equals (elementData [index])) {remove (index) ؛ العودة صحيح. }}} return false ؛ } / *** قم بإزالة العناصر في النطاق المحدد وفقًا لـ CORPRICT* param fromindex start* param toindex end* / protected void removerange (int fromindex ، int toindex) {rangecheck (fromIndex) ؛ RangeCheck (Toindex) ؛ // عدد العناصر المراد نقلها int numMoved = size - toindex ؛ // انقل العنصر خلف Toindex إلى FromIndex System.arrayCopy (ElementData ، Toindex ، ElementData ، FromIndex ، numMoved) ؛ // عدد العناصر المراد إزالتها int newsize = size- (toindex-fromindex) ؛ بينما (الحجم! = newsize) {elementData [-size] = null ؛ }} / *** اضبط قدرة الصفيف على السعة الفعلية* / public void trimtosize () {int length = elementData.Length ؛ if (size <leng) {object [] old = elementData ؛ elementData = arrays.copyof (elementData ، size) ؛ }} / *** تحويل عناصر المجموعة إلى صفيف* regurn* / كائن عام [] toarray () {return arrays.copyof (elementData ، size) ؛ } public <t> t [] tararray (t [] a) {if (A.Length <size) {return (t []) arrays.copyof (elementData ، size ، a.getClass ()) ؛ } // انسخ عنصر التجميع في Array Asystem.arrayCopy (ElementData ، 0 ، A ، 0 ، Size) ؛ if (A.Length> size) {for (int index = size ؛ index <A.Length ؛ index ++) {a [index] = null ؛ }} إرجاع أ ؛ } في الأساس ، يتعلق الأمر بتشغيل الصفيف واستخدام طرق C لتعيين القيم ونقلها. يمكنك عرض النص الأصلي بالتفصيل. لا توجد العديد من المشكلات في النص الأصلي باستثناء المتغير الخاص ، ويمكن أن يعمل الرمز بشكل مثالي. ستكون صعوبة هذا واستخدام متغير OldData في طريقة التوسع هي طريقتين للنظام ، ArrayCopy و Arrayist.copy () واستخدام متغير OldData في طريقة التوسع. هذا المتغير جيد حقا. في البداية ، لم أكن أعرف لماذا استخدمته على هذا النحو ، وسأشرح ذلك في نهاية النص الأصلي.
ما ورد أعلاه هو مثال على تنفيذ Java ArrayList الذي قدمه لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، يرجى ترك رسالة لي. سوف يرد المحرر لك في الوقت المناسب. شكرًا جزيلاً على دعمكم لموقع Wulin Network!