لماذا لا تقوم Java Map بتوسيع Collection؟


Answers

في حين أنك حصلت على عدد من الإجابات التي تغطي سؤالك بشكل عادل ، أعتقد أنه قد يكون من المفيد التراجع قليلاً ، وإلقاء نظرة على السؤال بشكل أكثر عمومية. وهذا يعني ، عدم النظر على وجه التحديد في كيفية كتابة مكتبة جافا ، والنظر في سبب كتابتها بهذه الطريقة.

تكمن المشكلة هنا في أن الوراثة لا تشكل إلا نوعًا واحدًا من القواسم المشتركة. إذا اخترت شيئين يبدو كلاهما "تشبه المجموعة" ، فيمكنك اختيار 8 أو 10 أشياء مشتركة بينها. إذا اخترت زوجًا مختلفًا من الأشياء "المشابهة للتجميع" ، فستشترك أيضًا في 8 أو 10 أشياء - ولكنها لن تكون بنفس 8 أو 10 أشياء مثل الزوج الأول.

إذا نظرت إلى أكثر من عشرة أشياء "شبيهة بالجماعة" ، فمن المحتمل أن يكون لكل واحد منهم شيئًا مثل 8 أو 10 سمات مشتركة مع واحد آخر على الأقل - ولكن إذا نظرت إلى ما يتم مشاركته عبر كل واحد منهم ، كنت لا شيء عمليا.

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

يأخذ البعض أيضًا خيارًا أساسيًا قائلاً: "هذا النوع من التجميع يدعم العملية X ، ولكن لا يُسمح لك باستخدامها ، من خلال اشتقاقها من فئة أساسية تحدد X ، ولكن محاولة استخدام فئة X المشتقة (على سبيل المثال" ، من خلال رمي استثناء).

هذا لا يزال يترك مشكلة واحدة: تقريبا بغض النظر عن الذي تتركه وتضع فيه ، سيكون عليك رسم خط متشدد بين الطبقات الموجودة وما هو خارج. وبغض النظر عن المكان الذي ترسم فيه هذا الخط ، فسوف يتبقى لك تقسيم واضح ، مصطنع ، بين بعض الأشياء المتشابهة تمامًا .

Question

لقد فوجئت بحقيقة أن Map<?,?> ليست Collection<?> .

اعتقدت أنها ستجعل الكثير من الإحساس إذا تم الإعلان عنها على هذا النحو:

public interface Map<K,V> extends Collection<Map.Entry<K,V>>

بعد كل شيء ، Map<K,V> هي مجموعة من Map.Entry<K,V> ، أليس كذلك؟

فهل هناك سبب وجيه لعدم تنفيذها على هذا النحو؟

بفضل Cletus للحصول على إجابة أكثر موثوقية ، ولكن ما زلت أتساءل لماذا ، إذا كان يمكنك بالفعل عرض Map<K,V> باسم Set<Map.Entries<K,V>> (عبر entrySet() ) ، فإنه لا يعمل لا مجرد تمديد تلك الواجهة بدلا من ذلك.

إذا كانت Map عبارة عن Collection ، فما هي العناصر؟ الجواب المعقول الوحيد هو "أزواج القيمة الرئيسية"

بالضبط ، interface Map<K,V> extends Set<Map.Entry<K,V>> سيكون رائعا!

ولكن هذا يوفر تجريدًا محدودًا جدًا (وليس مفيدًا) في Map .

ولكن إذا كان هذا هو الحال فلماذا يتم تحديد entrySet بواسطة الواجهة؟ يجب أن يكون مفيدا بطريقة أو بأخرى (وأعتقد أنه من السهل القول لهذا الموقف!).

لا يمكنك أن تسأل عن القيمة التي يحددها مفتاح معين ، ولا يمكنك حذف الإدخال لمفتاح معين دون معرفة القيمة التي تعينها.

أنا لا أقول أن هذا كل ما في الأمر إلى Map ! يمكن ويجب أن تبقي جميع الطرق الأخرى (باستثناء entrySet ، وهو زائدة الآن)!




إن إجابة cletus جيدة ، لكني أريد أن أضيف طريقة دلالية. للجمع بين كلاهما لا معنى له ، فكر في الحالة التي تضيفها إلى زوج القيمة الأساسية عبر واجهة المجموعة والمفتاح موجود بالفعل. تسمح واجهة الخريطة بربط قيمة واحدة فقط بالمفتاح. ولكن إذا قمت بإزالة الإدخال الموجود تلقائيًا باستخدام المفتاح نفسه ، فستكون المجموعة بعد إضافة الحجم نفسه كما كان من قبل - وهو أمر غير متوقع جدًا لمجموعة.




إذا نظرت إلى بنية البيانات المعنية ، فيمكنك بسهولة تخمين سبب عدم اعتبار Map جزءًا من Collection . تقوم كل Collection بتخزين قيمة مفردة حيث يقوم " Map بتخزين زوج القيمة الرئيسية. لذلك لا تتوافق الطرق في واجهة Collection واجهة Map . على سبيل المثال ، في Collection add(Object o) . ماذا سيكون هذا التنفيذ في Map . من غير المنطقي وجود مثل هذه الطريقة في Map . بدلا من ذلك لدينا طريقة put(key,value) في Map .

وينطبق نفس الوسيطة على addAll() remove() وأساليب removeAll() . لذا فإن السبب الرئيسي هو الاختلاف في طريقة تخزين البيانات في Map Collection . أيضا إذا كنت تتذكر واجهة Collection تطبيق واجهة Iterable أي أي واجهة مع .iterator() يجب أن تعيد طريقة تكرار والتي يجب أن تسمح لنا بالتكرار أكثر من القيم المخزنة في Collection . الآن ماذا ستعود مثل هذه الطريقة Map ؟ مكرر المفتاح أو إهداء القيمة؟ هذا لا معنى له أيضا.

هناك طرق يمكننا من خلالها التكرار عبر مفاتيح ومخازن القيم في Map ، وهذا هو الكيفية التي تكون بها جزءًا من إطار Collection .




تحتوي الخريطة على ثلاث مجموعات مختلفة: مجموعة مفاتيح ، ومجموعة إدخال ، ومجموعة من أزواج القيم الرئيسية .
يمكنك الحصول على أي من الثلاثة مع استدعاء طريقة واحدة.

يمكن القول أن مجموعة الأزواج الرئيسية فقط هي "المجموعة" ، وهي مجموعة غير طبيعية.
يمكنك أن تقول أن الخريطة عبارة عن مجموعة (في الواقع ، مجموعة) من Map.Entry ، ولكنها مجرد نوع من الغرابة والغرابة.
إنه أقل ملائمة لتحديد المجموعة بمجموعة قيمها أو مجموعة مفاتيحها. لذا ، وبدلاً من التشويش ، تمكنوا من الوصول إلى الثلاثة بسهولة ومتساوية.




مستقيم وبسيط. المجموعة هي واجهة تتوقع كائنًا واحدًا فقط ، حيث تتطلب الخريطة الثانية.

Collection(Object o);
Map<Object,Object>