1. مجموعات في جافا
فصول التجميع في Java هي الفصول الأكثر استخدامًا وأكثرها ملاءمة في برمجة Java. كفئة حاوية ، يمكن لفئة التجميع تخزين أي نوع من البيانات ، وبالطبع يمكنها أيضًا تخزين أنواع محددة مع الأدوية الجيلية (ولكن الأدوية الجيلية صالحة فقط خلال فترة التجميع وسيتم محوها في وقت التشغيل). ما يتم تخزينه في فئة التجميع هو مجرد إشارة إلى الكائن ، وليس إشارة إلى الكائن نفسه. يمكن توسيع قدرة فئة التجميع ديناميكيًا أثناء التشغيل ، كما توفر العديد من الأساليب المريحة ، مثل العثور على الاتحاد وتقاطع المجموعة.
2. هيكل فئة التجميع
تتضمن المجموعات في Java هياكل بيانات متعددة ، مثل القوائم المرتبطة ، والقوائم ، وجداول التجزئة ، وما إلى ذلك من حيث بنية الميراث للفئة ، يمكن تقسيمها إلى فئتين. واحد ورث من واجهة التجميع. يتضمن هذا النوع من المجموعات فئات التجميع مثل القائمة والمجموعة وقائمة الانتظار. يتم توريث الفئة الأخرى من واجهة الخريطة ، والتي تتضمن بشكل أساسي فئات التجميع المتعلقة بجداول التجزئة. دعونا نلقي نظرة على مخططات بنية الميراث لهاتين الفئتين:
1. قائمة ، تعيين وقائمة الانتظار
يمثل الخط المنقط الأخضر في الشكل التنفيذ ، ويمثل الخط الصلب الأخضر الميراث بين الواجهات ، ويمثل الخط الصلب الأزرق الميراث بين الفئات.
(1) القائمة: نستخدم المزيد من القوائم ، بما في ذلك ArrayList و LinkedList. الفرق بين هذين الاثنين هو أيضا واضح للغاية ، والتي يمكن رؤيتها من أسمائهم. يتم تنفيذ قائمة ArrayList الأساسية من خلال المصفوفات ، وبالتالي فإن سرعة الوصول العشوائية سريعة نسبيًا ، لكن الكفاءة منخفضة نسبيًا للحالات التي تكون فيها الإضافات والحذف المتكررة مطلوبة. بالنسبة إلى LinkedList ، يتم تنفيذ الطبقة الأساسية من خلال القوائم المرتبطة ، وبالتالي فإن عملية الإضافة والحذف أسهل في إكمالها ، لكن كفاءة الوصول العشوائي منخفضة نسبيًا.
دعونا نلقي نظرة أولاً على كفاءة الإدراج على حد سواء:
package com.paddx.test.collection ؛ استيراد java.util.arraylist ؛ استيراد java.util.linkedList ؛ فئة عامة قائمة {public static void main (string [] args) {for (int i = ؛ i <؛ i ++) {} start = system.currenttimillis () ؛ LinkedList <integer> () ؛ for (int i = ؛ i <؛ i ++) {linkedList.add (، i) ؛} long end = system.currentTimeMillis () ؛ system.out.println (end - start) i = ؛ i <؛ i ++) {ArrayList.add (، i) ؛} system.out.println (System.CurrentTimeMillis () - end) ؛}}فيما يلي نتائج التنفيذ المحلي:
ثلاثة وعشرين
1227
يمكن ملاحظة أنه في هذه الحالة ، تكون كفاءة الإدراج في LinkedList أعلى بكثير من وكفاءة ArrayList ، بالطبع هذا هو الوضع المتطرف نسبيًا. دعنا نقارن كفاءة الوصول العشوائي بين الاثنين:
package com.paddx.test.collection ؛ استيراد java.util.arraylist ؛ استيراد java.util.linkedList ؛ استيراد java.util.random ؛ فئة عامة قائمة {public static void main (string [] args) {عشوائي عشوائي جديد () ؛ لـ int i = ؛ LinkedList <integer> () ؛ for (int i = ؛ i <؛ i ++) {linkedList.add (i) ؛} ArrayList <integer> arrayList = new ArrayList <integer> () ؛ لـ (int i = ؛ i <؛ i ++) {ArrayList.add (i) ؛} start long = system.currentTimeMillis () ؛ لـ (int i = ؛ i <؛ i ++) {int j = random.nextint (i+) ؛ int k = linkedList.get (j) ؛} long end = system.currentTimEmillis () ؛ system.out.println (end - start) ؛ for (int i = ؛ i ++) ArrayList.get (j) ؛} system.out.println (System.CurrentTimeMillis () - end) ؛}}هذه هي نتيجة إعدامي:
5277
6
من الواضح أن كفاءة الوصول العشوائية لـ ArrayList هي عدة أوامر ذات حجم أعلى من LinkedList. من خلال هاتين القطعتين من التعليمات البرمجية ، يجب أن نكون قادرين على معرفة الفرق بشكل أكثر وضوحًا بين LinkedList و ArrayList وسيناريوهات التكيف. بالنسبة إلى Vector ، فهو إصدار آمن مؤشر ترابط من ArrayList ، في حين أن المكدس يتوافق مع بنية بيانات المكدس. يتم استخدام هذين الاثنين بشكل متكرر ، لذلك لن أعطي مثالاً هنا.
(2) قائمة الانتظار: بشكل عام ، يمكن القيام به مباشرة باستخدام LinkedList. يمكن رؤيته أيضًا من مخطط الفئة أعلاه أن LinkedList يرث من Deque ، لذلك LinkedList لديها وظيفة قائمة انتظار مزدوجة. يتميز PriorityQueue بتوفير أولوية لكل عنصر ، وسيتم إعطاء أولوية عناصر ذات أولوية عالية من قائمة الانتظار.
(3) المجموعة: الفرق الرئيسي بين المجموعة والقائمة هو أن المجموعة لا تسمح بتكرار العناصر ، في حين أن القائمة يمكن أن تسمح بتكرار العناصر. للحكم على تكرار العناصر ، نحتاج إلى اتخاذ قرار بناءً على طريقة تجزئة الكائن والطريقة المتساوية. هذا هو السبب في أننا عادة ما نتجاوز طريقة Hashcode وطريقة تساوي فئات العناصر في مجموعة. دعنا نأخذ مثالاً لمعرفة الفرق بين المجموعة والقائمة ، وكذلك دور طريقة الترميز وطريقة متساوية:
package com.paddx.test.collection ؛ استيراد java.util.arraylist ؛ استيراد java.util.hashset ؛ استيراد java.util.set ؛ الطبقة العامة settest {public static void main (string [] args) الشخص ("LXP" ، 20) ؛ ArrayList <Person> list = new ArrayList <Person> () ؛ list.add (p1) ؛ system.out.println ("---------------") ؛ list.add (p2) ؛ system.out.println ("---------------------") list.size ()) ؛ system.out.println ("---------------") ؛ set <Person> set = new hassset <Person> () ؛ set.add (p1) ؛ system.out.println ("---------------") size = "+set.size ()) ؛} الشخص الثابت {اسم السلسلة الخاصة ؛ int ation ؛ الشخص العام (اسم السلسلة ، int ens) {this.name = name ؛ this.age = age ؛}@overridepublic boolean يساوي (كائن o) {system.out.println (" call equals () ؛ name = ! = o.getClass ()) إرجاع خطأ ؛ شخص شخص = (شخص) o ؛ اسم الإرجاع. نتائج تنفيذ الكود أعلاه هي كما يلي:
------------
------------
حجم القائمة = 3
---- خط الانقسام ----
استدعاء hashcode () ، العمر = 10
------------
استدعاء hashcode () ، العمر = 10
استدعاء equals () ؛ name = lxp
------------
استدعاء hashcode () ، العمر = 20
ضبط الحجم = 2
من النتائج ، لا يتم إجراء عمليات إضافية عند إضافة العنصر إلى القائمة ويمكن تكرارها. قبل الانضمام ، تحتاج إلى تنفيذ طريقة HashCode أولاً. إذا كانت القيمة التي تم إرجاعها موجودة بالفعل في المجموعة ، فأنت بحاجة إلى متابعة تنفيذ طريقة متساوٍ. إذا كانت النتيجة التي تم إرجاعها بواسطة طريقة متساوٍ صحيحة أيضًا ، فإنها تثبت أن العنصر موجود بالفعل ، وسيتم كتابة العنصر الجديد من قبل العنصر القديم. إذا كانت قيمة Hashcode التي تم إرجاعها مختلفة ، فستضيف مجموعة مباشرة. تذكر هنا أنه بالنسبة للعناصر الموجودة في المجموعة ، يجب أن تكون العناصر ذات قيم التجزئة المختلفة غير متكافئة ، ولكن بالنسبة للعناصر التي تحتوي على قيم hashcode قد تكون هي نفسها.
الفرق بين Hashset و LinkedHashset هو أن الأخير يمكن أن يضمن أن ترتيب العناصر المدرجة في المجموعة يتسق مع ترتيب الإخراج. الفرق بين Tresset هو أن فرزه يتم فرزه في المقارنة ، وعلى الافتراضي ، يتم ترتيبه بترتيب تصاعدي بالترتيب الطبيعي للشخصيات.
(4) Iterable: من هذا الرقم ، يمكنك أن ترى أن فئة التجميع ترث من Iterable. تتمثل وظيفة هذه الواجهة في توفير اجتياز العناصر ، أي أن جميع فئات التجميع (باستثناء الفئات المتعلقة بالخريطة) توفر وظائف اجتياز العناصر. يحتوي Iterfer على مكرر ITerator ، ورمز المصدر الخاص به كما يلي. إذا كنت على دراية بوضع التكرار ، فيجب أن يكون من السهل فهمه.
iterator الواجهة العامة <e> {boolean hasnext () ؛ e next () ؛ void remove () ؛}2. الخريطة:
أكبر ميزة لجمع نوع الخريطة هي أن كفاءة البحث عالية نسبيًا ، ويمكن تحقيق التعقيد الزمني لـ O (1) بشكل مثالي. الخريطة الأكثر استخداما هي hashmap. الفرق بين LinkedHashMap و HashMap هو أن الأول يمكن أن يضمن أن ترتيب العناصر المدرجة في المجموعة يتسق مع ترتيب الإخراج. الفرق بين هذين و Treemap هو أن Treemap يتم فرزها وفقًا للقيم الرئيسية. بطبيعة الحال ، فإن تنفيذها الأساسي لها أيضًا اختلافات أساسية. على سبيل المثال ، الطبقة الأساسية من hashmap هي جدول التجزئة ، في حين أن الطبقة الأساسية من treemap هي شجرة. دعونا الآن نلقي نظرة على الفرق بين Treemap و LinkedHashMap:
package com.paddx.test.collection ؛ استيراد java.util.iterator ؛ استيراد java.util.linkedHashMap ؛ استيراد java.util.map ؛ استيراد java.util.treemap ؛ string> {string> {string> {string> string <string> string <string> linkedMap = new LinkedHashMap <string ، string> () ؛ treemap.put ("b" ، null) ؛ treemap.put ("c" ، null) ؛ treemap.keyset (). iterator () ؛ iter.hasnext () ؛) {system.out.println ("treemap ="+iter.next ()) ؛} system.out.prin tln ("---------- 分割线 ---------") ؛ linkedMap.put ("b" ، null) ؛ linkedMap.put ("c" ، null) ؛ linkedMap.put ("a" ، null) ؛ for (iterator <string> iter = linkedmap.keyset (). iterator () ؛ iter.hasnext () ؛) {system.out.println ("linkedhashmap ="+iter.next ()) ؛}}} قم بتشغيل الرمز أعلاه ونتيجة التنفيذ على النحو التالي:
treemap = أ
treemap = ب
treemap = ج
-----------------------
LinkedHashMap = ب
LinkedHashMap = ج
LinkedHashMap = أ
من نتائج التشغيل ، من الواضح أن الفرق بين Treemap و LinkedHashMap ينظر بوضوح إلى. السابق هو الإخراج عن طريق فرز السلسلة ، في حين أن الأخير هو الإخراج حسب أمر الإدراج. يمكن أن يجد القراء الدقيقون أن الفرق بين HashMap و Treemap يتسق مع الاختلافات المذكورة سابقًا بين Hashset و Treeset. عند إجراء تحليل التعليمات البرمجية المصدر في المستقبل ، يمكننا أن نرى أن Hashset و Treeset يتم تنفيذها بشكل أساسي من خلال hashmap و treemap على التوالي ، وبالتالي فإن اختلافاتها هي نفسها بشكل طبيعي. نادرا ما تستخدم علامة التجزئة الآن. الفرق الرئيسي من hashmap هو أن علامة التجزئة آمنة الخيط ، ولكن بسبب انخفاض كفاءته ، عادة ما يتم استخدام hashmap. في بيئة متعددة الخيوط ، عادة ما يتم استخدام CurrentHashMap بدلاً من ذلك.
3. ملخص
تقدم هذه المقالة فقط إطار مجموعة Java وعلاقة الميراث ككل. بالإضافة إلى الفئات أعلاه ، توفر المجموعات أيضًا فئتين للأداة: المجموعات والصفائف. بالإضافة إلى ذلك ، يرتبط الفرز في المجموعة ارتباطًا وثيقًا بالمقارنة والمقارنة. في مقالة لاحقة ، سيتم تحليل رمز مصدر تنفيذ الفئة المذكور أعلاه في JDK بالتفصيل.