Java Map कलेक्शन का विस्तार क्यों नहीं करता है?


146

मैं इस तथ्य से हैरान था कि Map<?,?>ए नहीं है Collection<?>

मैंने सोचा था कि अगर यह इस तरह से घोषित किया गया था, तो यह बहुत मायने रखेगा:

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

सब के बाद, एक Map<K,V>का एक संग्रह है Map.Entry<K,V>, है ना?

तो क्या इसका एक अच्छा कारण है कि इसे इस तरह लागू नहीं किया गया है?


एक सबसे आधिकारिक जवाब के लिए कि्लिटस के लिए धन्यवाद, लेकिन मैं अभी भी सोच रहा हूँ क्यों, अगर आप पहले से ही एक देख सकते हैं 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, जो अब बेमानी है)!


1
घटना सेट <Map.Entry <K, V >> वास्तव में
मौरिस पेरी

3
यह सिर्फ नहीं है। यह एक तार्किक निष्कर्ष होने के बजाय एक राय पर आधारित है (जैसा कि डिज़ाइन FAQ में वर्णित है)। वैकल्पिक दृष्टिकोण के लिए C ++ STL ( sgi.com/tech/stl/table_of_contents.html ) में कंटेनरों के डिज़ाइन को देखें जो कि Stepanov के संपूर्ण और शानदार विश्लेषण पर आधारित है।
बेलाज

जवाबों:


123

से जावा संग्रह एपीआई डिजाइन पूछे जाने वाले प्रश्न :

मानचित्र संग्रह का विस्तार क्यों नहीं करता है?

यह डिजाइन द्वारा किया गया था। हमें लगता है कि मैपिंग संग्रह नहीं हैं और संग्रह मैपिंग नहीं हैं। इस प्रकार, यह मानचित्र के लिए संग्रह इंटरफ़ेस (या इसके विपरीत) का विस्तार करने के लिए बहुत कम समझ में आता है।

यदि एक मानचित्र एक संग्रह है, तो क्या तत्व हैं? एकमात्र उचित उत्तर "कुंजी-मूल्य जोड़े" है, लेकिन यह बहुत सीमित (और विशेष रूप से उपयोगी नहीं) मानचित्र अमूर्त प्रदान करता है। आप यह नहीं पूछ सकते कि किसी दिए गए मुख्य नक्शे का क्या मूल्य है, और न ही आप किसी दिए गए कुंजी के लिए प्रविष्टि को हटा सकते हैं, यह जाने बिना कि यह किस मूल्य के नक्शे के लिए है।

मानचित्र का विस्तार करने के लिए संग्रह बनाया जा सकता है, लेकिन यह सवाल उठाता है: चाबियाँ क्या हैं? वास्तव में कोई संतोषजनक जवाब नहीं है, और कोई भी व्यक्ति अप्राकृतिक इंटरफ़ेस के लिए मजबूर होता है।

मैप्स को (कुंजी, मान या जोड़े के) संग्रह के रूप में देखा जा सकता है, और यह तथ्य मैप्स (कीसेट, एंट्रीसेट और वैल्यू) पर तीन "कलेक्शन व्यू ऑपरेशंस" में परिलक्षित होता है। हालांकि, यह सिद्धांत में, तत्वों को मैप मैपिंग सूचकांकों के रूप में एक सूची को देखने के लिए संभव है, यह गंदा संपत्ति है कि सूची से एक तत्व को हटाने से हटाए गए तत्व से पहले हर तत्व से जुड़ी कुंजी को बदल दिया जाता है। इसीलिए हमारे पास सूचियों पर मानचित्र दृश्य संचालन नहीं है।

अद्यतन: मुझे लगता है कि उद्धरण अधिकांश प्रश्नों का उत्तर देता है। यह एक विशेष रूप से उपयोगी अमूर्त नहीं होने वाली प्रविष्टियों के संग्रह के बारे में भाग पर ध्यान देने योग्य है। उदाहरण के लिए:

Set<Map.Entry<String,String>>

अनुमति देंगे:

set.add(entry("hello", "world"));
set.add(entry("hello", "world 2");

(एक entry()विधि है कि एक बनाता है संभालनेMap.Entry उदाहरण )

Mapके लिए अद्वितीय कुंजियों की आवश्यकता होती है, इसलिए यह इसका उल्लंघन होगा। या यदि आप Setप्रविष्टियों पर अद्वितीय कुंजी लगाते हैं, तो यह वास्तव में नहीं हैSet में सामान्य अर्थों में नहीं है। यह एक Setऔर प्रतिबंध के साथ है।

संभवतः आप के लिए equals()/ hashCode()संबंध कह सकते हैंMap.Entry विशुद्ध रूप से कुंजी पर था, लेकिन यहां तक ​​कि मुद्दे भी हैं। इससे भी महत्वपूर्ण बात, क्या यह वास्तव में कोई मूल्य जोड़ता है? एक बार जब आप कोने के मामलों को देखना शुरू करते हैं तो आपको यह अमूर्तन टूट सकता है।

यह ध्यान देने योग्य है कि HashSetवास्तव में ए के रूप में लागू किया गया हैHashMap , न कि दूसरे तरीके से। यह विशुद्ध रूप से एक कार्यान्वयन विवरण है लेकिन फिर भी दिलचस्प है।

entrySet()अस्तित्व में आने का मुख्य कारण ट्रैवर्सल को सरल बनाना है ताकि आपको कुंजियों का पता लगाने की जरूरत न पड़े और फिर कुंजी की खोज करें। इसे प्रथम दृष्टया सबूत के रूप में न लें कि प्रविष्टियों (imho) का Mapहोना चाहिए Set


1
अद्यतन बहुत आश्वस्त है, लेकिन वास्तव में, सेट दृश्य द्वारा entrySet()समर्थित है remove, जबकि यह समर्थन नहीं करता है add(शायद फेंकता है UnsupportedException)। इसलिए मैं आपकी बात देख रहा हूं, लेकिन फिर से, मैं ओपी की बात भी देखता हूं, .. (मेरी खुद की राय मेरे ही जवाब में बताई गई है ..)
Enno Shioji

1
ज़ेवी एक अच्छा बिंदु लाता है। उन सभी जटिलताओं के कारण ही इसे देखा addजा सकता है जैसे कि entrySet()दृश्य कैसे करता है: कुछ संचालन की अनुमति दें और दूसरों को अनुमति न दें। एक स्वाभाविक प्रतिक्रिया, ज़ाहिर है, "किस प्रकार का Setसमर्थन नहीं करता हैadd ?" - ठीक है, अगर इस तरह के व्यवहार के लिए स्वीकार्य है entrySet(), तो यह क्यों स्वीकार्य नहीं है this? यही कारण है कि कहा, मैं कर रहा हूँ ज्यादातर कारण है कि इस तरह के एक महान विचार नहीं है की पहले से ही आश्वस्त के रूप में मैं एक बार सोचा, लेकिन मैं अभी भी, लगता है कि अगर केवल एक अच्छा एपीआई / OOP डिजाइन बनाता है की मेरी अपनी समझ को समृद्ध करने के लिए इसे आगे बहस के लायक है।
पोलीगेनेल लुब्रिकेंट्स

3
FAQ से उद्धरण का पहला पैराग्राफ मज़ेदार है: "हम महसूस करते हैं ... इस प्रकार ... थोड़ा समझ में आता है"। मुझे नहीं लगता कि "महसूस" और "भावना" एक निष्कर्ष बनाते हैं; ओ)
पीटर विप्रमैन

मानचित्र का विस्तार करने के लिए संग्रह बनाया जा सकता है ? यकीन नहीं होता, लेखक Collectionविस्तार के लिए क्यों सोचता है Map?
ओवरएक्सचेंज

11

हालांकि आपने कई ऐसे उत्तर प्राप्त किए हैं जो आपके प्रश्न को सीधे कवर करते हैं, मुझे लगता है कि यह थोड़ा पीछे हटने के लिए उपयोगी हो सकता है, और प्रश्न को थोड़ा और सामान्य रूप से देखें। यही है, विशेष रूप से यह देखने के लिए नहीं कि जावा लाइब्रेरी कैसे लिखी जाती है, और यह देखें कि ऐसा क्यों लिखा गया है।

यहाँ समस्या यह है कि विरासत में केवल एक प्रकार की समानता है। यदि आप दो चीजें निकालते हैं, जो दोनों "संग्रह-समान" लगती हैं, तो आप संभवतः एक 8 या 10 चीजें चुन सकते हैं जो उनके पास हैं। यदि आप "संग्रह-जैसी" चीजों की एक अलग जोड़ी निकालते हैं, तो वे भी सामान्य रूप से 8 या 10 चीजें लेंगे - लेकिन वे समान नहीं होंगे पहली जोड़ी 8 या 10 चीजें ।

यदि आप एक दर्जन या इतने अलग-अलग "संग्रह-जैसी" चीजों को देखते हैं, तो उनमें से हर एक के पास संभवतः कम से कम एक दूसरे के साथ 8 या 10 विशेषताओं की तरह कुछ होगा - लेकिन अगर आप देखते हैं कि हर में क्या साझा किया गया है? एक उनमें से, आप व्यावहारिक रूप से कुछ भी नहीं छोड़ रहे हैं।

यह एक ऐसी स्थिति है जो वंशानुक्रम (विशेष रूप से एकल विरासत) सिर्फ अच्छी तरह से मॉडल नहीं करता है। उनमें से कोई भी स्पष्ट विभाजन रेखा नहीं है, जो वास्तव में संग्रह हैं और जो नहीं हैं - लेकिन यदि आप एक सार्थक संग्रह वर्ग को परिभाषित करना चाहते हैं, तो आप उनमें से कुछ को छोड़ने के साथ फंस गए हैं। यदि आप उनमें से कुछ को ही छोड़ते हैं, तो आपका संग्रह वर्ग केवल काफी विरल इंटरफ़ेस प्रदान करने में सक्षम होगा। यदि आप अधिक बाहर छोड़ते हैं, तो आप इसे अधिक समृद्ध इंटरफ़ेस दे पाएंगे।

कुछ लोग मूल रूप से यह कहने का विकल्प भी लेते हैं: "इस प्रकार का संग्रह ऑपरेशन X का समर्थन करता है, लेकिन आपको X को परिभाषित करने वाले आधार वर्ग से प्राप्त करके इसका उपयोग करने की अनुमति नहीं है, लेकिन व्युत्पन्न वर्ग 'X का उपयोग करने का प्रयास विफल रहता है (जैसे , एक अपवाद फेंककर)।

यह अभी भी एक समस्या छोड़ देता है: लगभग परवाह किए बिना, जिसमें से आप बाहर निकलते हैं और जिसे आप डालते हैं, आपको कक्षा में और बाहर क्या हैं, के बीच एक कठिन रेखा खींचनी होगी। इससे कोई फर्क नहीं पड़ता कि आप उस रेखा को कहां तक ​​खींचते हैं, आप कुछ चीजों के बीच स्पष्ट, बल्कि कृत्रिम, विभाजन के साथ छोड़ दिए जाएंगे काफी समान।


10

मुझे लगता है क्यों व्यक्तिपरक है।

सी # में, मुझे लगता है कि Dictionaryएक संग्रह का विस्तार या कम से कम लागू होता है:

public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, 
    ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, 
    IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback

फेरो स्मालतक में भी:

Collection subclass: #Set
Set subclass: #Dictionary

लेकिन कुछ विधियों के साथ एक विषमता है। उदाहरण के लिए, मूल्यों collect:को do:लेते हुए एसोसिएशन (एक प्रविष्टि के बराबर) ले जाएगा। वे keysAndValuesDo:प्रवेश द्वारा शब्दकोश को पुनरावृत्त करने के लिए एक और तरीका प्रदान करते हैं । Add:एक सहयोग लेता है, लेकिन remove:"दबा दिया गया":

remove: anObject
self shouldNotImplement 

तो यह निश्चित रूप से उल्लेखनीय है, लेकिन वर्ग पदानुक्रम के बारे में कुछ अन्य मुद्दों की ओर जाता है।

जो बेहतर है वह व्यक्तिपरक है।


3

क्लेटस का उत्तर अच्छा है, लेकिन मैं एक अर्थ संबंधी दृष्टिकोण जोड़ना चाहता हूं। दोनों को संयोजित करने का कोई मतलब नहीं है, इस मामले के बारे में सोचें जो आप संग्रह इंटरफ़ेस के माध्यम से एक कुंजी-मूल्य-जोड़ी जोड़ते हैं और कुंजी पहले से मौजूद है। मैप-इंटरफ़ेस कुंजी के साथ जुड़े केवल एक मूल्य की अनुमति देता है। लेकिन अगर आप स्वचालित रूप से एक ही कुंजी के साथ मौजूदा प्रविष्टि को हटाते हैं, तो संग्रह में पहले के समान आकार जोड़ने के बाद है - एक संग्रह के लिए बहुत अप्रत्याशित।


4
यह कैसे Setकाम करता है, और कार्यान्वित Set करता है Collection
Lii

2

जावा संग्रह टूट गए हैं। एक लापता इंटरफ़ेस है, कि संबंध। इसलिए, मानचित्र का विस्तार संबंध सेट तक विस्तृत है। संबंध (जिसे बहु-मानचित्र भी कहा जाता है) में अद्वितीय नाम-मूल्य जोड़े हैं। मैप्स (उर्फ "फ़ंक्शंस"), अद्वितीय नाम (या कुंजियाँ) हैं, जो निश्चित रूप से मूल्यों के लिए मैप करते हैं। अनुक्रम मैप्स का विस्तार करते हैं (जहां प्रत्येक कुंजी एक पूर्णांक है 0)। बैग (या बहु-सेट) मैप्स का विस्तार करते हैं (जहां प्रत्येक कुंजी एक तत्व है और प्रत्येक मान बैग में तत्व प्रकट होने की संख्या की संख्या है)।

यह संरचना "संग्रह" की एक श्रृंखला के प्रतिच्छेदन, संघ आदि की अनुमति देगा। इसलिए, पदानुक्रम होना चाहिए:

                                Set

                                 |

                              Relation

                                 |

                                Map

                                / \

                             Bag Sequence

Sun / Oracle / Java ppl - कृपया इसे अगली बार ठीक करें। धन्यवाद।


4
मैं इन काल्पनिक इंटरफेस के लिए एपीआई के विस्तृत विवरण देखना चाहता हूं। यकीन नहीं है कि मैं एक अनुक्रम (उर्फ सूची) चाहूंगा जहां कुंजी एक पूर्णांक थी; यह एक विशाल प्रदर्शन हिट की तरह लगता है।
लॉरेंस Dol

यह सही है, एक अनुक्रम एक सूची है - इसलिए अनुक्रम सूची का विस्तार करता है। मुझे नहीं पता कि आप इसे एक्सेस कर सकते हैं, लेकिन यह दिलचस्प पोर्टल
citation.cfm

@SoftwareMonkey यहां एक और लिंक है। अंतिम लिंक एपीआई के javadoc का लिंक है। zedlib.sourceforge.net
xagyg

@SoftwareMonkey मैं अनायास स्वीकार करता हूं कि डिजाइन यहां मेरी प्राथमिक चिंता है। मैं मान रहा हूं कि ओरेकल / सन में गुरुओं को इसमें से हेक को अनुकूलित किया जा सकता है।
xagyg

मैं असहमत हूं। यह कैसे पकड़ सकता है कि "मानचित्र एक-सेट है" यदि आप हमेशा अपने सेट में डोमेन के गैर-सदस्य तत्वों को नहीं जोड़ सकते हैं (उदाहरण के लिए @cletus के उत्तर में)।
ईनपोकलम

1

यदि आप संबंधित डेटा संरचना को देखते हैं तो आप आसानी से अनुमान लगा सकते हैं कि 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रूपरेखा का एक हिस्सा है ।


There are ways in which we can iterate over keys and values stores in a Map and that is how it is a part of Collection framework.क्या आप इसके लिए एक कोड उदाहरण दिखा सकते हैं?
रामेनशेफ

यह बहुत अच्छी तरह से समझाया गया था। मुझे ये अब मिला। धन्यवाद!
अमीर मेम

add(Object o)किसी Entry<ClassA, ClassB>वस्तु को जोड़ना एक कार्यान्वयन होगा । A Mapको माना जा सकता हैCollection of Tuples
LIvanov

0

वास्तव में, interface Map<K,V> extends Set<Map.Entry<K,V>>बहुत अच्छा होगा!

दरअसल, अगर ऐसा होता implements Map<K,V>, Set<Map.Entry<K,V>>, तो मैं सहमत होता हूं .. यह स्वाभाविक भी लगता है। लेकिन यह बहुत अच्छी तरह से काम नहीं करता है, है ना? मान लीजिए कि हमारे पास है HashMap implements Map<K,V>, Set<Map.Entry<K,V>, LinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V>आदि ... यह सब अच्छा है, लेकिन अगर आपके पास थाentrySet() , तो कोई भी उस पद्धति को लागू करना नहीं भूलेगा, और आप सुनिश्चित कर सकते हैं कि आप किसी भी मानचित्र के लिए प्रविष्टिसेट प्राप्त कर सकते हैं, जबकि आप उम्मीद नहीं कर रहे हैं कि कार्यान्वयनकर्ता ने दोनों इंटरफेस को लागू किया है ...

मेरे पास नहीं होने का कारण interface Map<K,V> extends Set<Map.Entry<K,V>>बस है, क्योंकि और भी तरीके होंगे। और आखिरकार, वे अलग चीजें हैं, है ना? व्यावहारिक रूप से भी, अगर मैं map.आईडीई में हिट करता हूं, तो मैं देखना नहीं चाहता हूं .remove(Object obj), और .remove(Map.Entry<K,V> entry)क्योंकि मैं ऐसा नहीं कर hit ctrl+space, r, returnसकता और इसके साथ किया जा सकता है।


यह मुझे लगता है कि यदि कोई दावा कर सकता है, शब्दार्थ, कि "ए मैप इज-ए सेट ऑन मैप.इंट्री" तो कोई संबंधित पद्धति को लागू करने से परेशान होगा; और अगर कोई यह बयान नहीं दे सकता है, तो कोई भी ऐसा नहीं करेगा - यानी यह परेशानियों के बारे में होना चाहिए।
ईनपोकलम

0

Map<K,V>के Set<Map.Entry<K,V>>बाद से विस्तार नहीं करना चाहिए :

  • आप उसी कुंजी के साथ अलग-अलग s जोड़ नहीं सकते , लेकिनMap.EntryMap
  • आप एक ही कुंजी के साथ अलग-अलग एस जोड़ सकते हैं ।Map.EntrySet<Map.Entry>

... यह @cletus 'के उत्तर के दूसरे भाग के घी का संक्षिप्त विवरण है।
einpoklum

-2

सीधे और सरल। संग्रह एक इंटरफ़ेस है जो केवल एक ऑब्जेक्ट की उम्मीद कर रहा है, जबकि मानचित्र को दो की आवश्यकता होती है।

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

अच्छा त्रिनिदाद, आपके उत्तर हमेशा सरल और संक्षिप्त हैं।
सियाराम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.