सूची <मानचित्र <स्ट्रिंग, स्ट्रिंग >> बनाम सूची <? मानचित्र का विस्तार <स्ट्रिंग, स्ट्रिंग >>


129

क्या इसमें कोई अंतर है

List<Map<String, String>>

तथा

List<? extends Map<String, String>>

?

यदि कोई अंतर नहीं है, तो उपयोग करने का क्या लाभ है ? extends?


2
मुझे जावा बहुत पसंद है लेकिन यह उन चीजों में से एक है जो अच्छी नहीं है ...
मिते मित्रेस्की

4
मुझे लगता है कि अगर हम इसे "कुछ भी जो विस्तार करते हैं ..." की तरह पढ़ते हैं, तो यह स्पष्ट हो जाता है।
कचरा

अविश्वसनीय, लगभग 3 दिनों में 12K से अधिक दृश्य? !!
Eng.Fouad

5
यह हैकर न्यूज के फ्रंट पेज पर पहुंच गया। बधाई।
r3st0r3 19

1
@ Eng.Found यहाँ यह है। अब फ्रंट पेज पर नहीं है, लेकिन कल था। news.ycombinator.net/item?id=3751901 (कल भारत में यहां मध्य रविवार हो रहा है।)
r3st0r3

जवाबों:


180

अंतर यह है कि, उदाहरण के लिए, ए

List<HashMap<String,String>>

एक है

List<? extends Map<String,String>>

लेकिन नहीं

List<Map<String,String>>

इसलिए:

void withWilds( List<? extends Map<String,String>> foo ){}
void noWilds( List<Map<String,String>> foo ){}

void main( String[] args ){
    List<HashMap<String,String>> myMap;

    withWilds( myMap ); // Works
    noWilds( myMap ); // Compiler error
}

आप एक लगता होगा Listकी HashMapएक होना चाहिए Listकी Mapहै, लेकिन इसका कोई खास कारण है क्यों यह नहीं है:

मान लीजिए आप कर सकते हैं:

List<HashMap<String,String>> hashMaps = new ArrayList<HashMap<String,String>>();

List<Map<String,String>> maps = hashMaps; // Won't compile,
                                          // but imagine that it could

Map<String,String> aMap = Collections.singletonMap("foo","bar"); // Not a HashMap

maps.add( aMap ); // Perfectly legal (adding a Map to a List of Maps)

// But maps and hashMaps are the same object, so this should be the same as

hashMaps.add( aMap ); // Should be illegal (aMap is not a HashMap)

तो यही कारण है कि एक Listके HashMapएक नहीं होना चाहिए Listकी Mapहै।


6
फिर भी, HashMapएक है Mapबहुरूपता की वजह से।
Eng.Fouad

46
ठीक है, लेकिन एक Listके HashMapएक नहीं है Listकी Mapरों।
सच्चाई २१'१२ को १२:२६


अच्छा उदाहरण। यह भी ध्यान देने योग्य है कि यदि आप घोषणा करते हैं List<Map<String,String>> maps = hashMaps; और HashMap<String,String> aMap = new HashMap<String, String>();, तब भी आप पाएंगे कि maps.add(aMap);अवैध है जबकि hashMaps.add(aMap);कानूनी है। इसका उद्देश्य गलत प्रकारों को जोड़ना रोकना है, लेकिन यह सही प्रकारों को जोड़ने की अनुमति नहीं देगा (संकलनकर्ता संकलन समय के दौरान "सही" प्रकार का निर्धारण नहीं कर सकता है)
Raze

@ रेज़ न, वास्तव में आप एक सूची में जोड़ सकते हैं , आपके दोनों उदाहरण कानूनी हैं, अगर मैं उन्हें सही ढंग से पढ़ रहा हूं। HashMapMap
सच्चाई

24

आप List<NavigableMap<String,String>>पहले जैसे प्रकारों के साथ अभिव्यक्ति प्रदान नहीं कर सकते ।

(आप को पता है तुम क्यों नहीं सौंप सकते चाहते हैं List<String>के लिए List<Object>एक को देखने के असंख्य इतने पर अन्य प्रश्न।)


1
आगे बता सकते हैं? मैं समझ सकता हूँ या अच्छे अभ्यास के लिए कोई लिंक?
समीर मंगरोलिया

3
@ आमिर ने क्या समझाया? List<String>का उपप्रकार नहीं है List<Object>? - देखें, उदाहरण के लिए, stackoverflow.com/questions/3246137/…
टॉम हैटिन -

2
इससे यह स्पष्ट नहीं होता कि अंतर क्या है या इसके साथ क्या है ? extends। न ही यह सुपर / उपप्रकारों या सह / विरोधाभासी (यदि कोई है) के साथ सहसंबंध की व्याख्या करता है।
हाबिल

16

अन्य उत्तरों में मुझे जो याद आ रहा है, वह इस संदर्भ में है कि यह सामान्य और विशेष रूप से सह-और विपरीत और उप- और सुपरटिप्स (यानी, बहुरूपता) से कैसे संबंधित है। यह अच्छी तरह से ओपी द्वारा समझा जा सकता है, लेकिन सिर्फ मामले में, यहाँ यह जाता है:

सहप्रसरण

आप एक वर्ग है, तो Automobile, तो Carऔर Truckउनके उपप्रकार हैं। किसी भी कार को प्रकार ऑटोमोबाइल के एक चर को सौंपा जा सकता है, यह OO में अच्छी तरह से जाना जाता है और इसे बहुरूपता कहा जाता है। Covariance इसी सिद्धांत का उपयोग जेनेरिक या डेलिगेट्स के साथ परिदृश्यों में करता है। जावा में प्रतिनिधि (अभी तक) नहीं हैं, इसलिए यह शब्द केवल जेनरिक पर लागू होता है।

मैं मानक पॉलीमॉर्फिज़्म के रूप में सहसंयोजक के बारे में सोचता हूं कि आप बिना सोचे-समझे काम करने की क्या उम्मीद करेंगे, क्योंकि:

List<Car> cars;
List<Automobile> automobiles = cars;
// You'd expect this to work because Car is-a Automobile, but
// throws inconvertible types compile error.

हालाँकि, त्रुटि का कारण सही है: List<Car> से विरासत में नहीं मिलता है List<Automobile>और इस प्रकार एक दूसरे को नहीं सौंपा जा सकता है। केवल सामान्य प्रकार के मापदंडों का एक अंतर्निहित संबंध है। कोई यह सोच सकता है कि जावा कंपाइलर बस इतना स्मार्ट नहीं है कि वह आपके परिदृश्य को ठीक से समझ सके। हालाँकि, आप उसे संकेत देकर कंपाइलर की मदद कर सकते हैं:

List<Car> cars;
List<? extends Automobile> automobiles = cars;   // no error

contravariance

सह-विचरण का उल्टा विपरीत है। जहां सहसंयोजक में पैरामीटर प्रकार का एक उप-प्रकार संबंध होना चाहिए, वहीं प्रतिवाद में उनके पास एक सुपर-टाइप संबंध होना चाहिए। इसे एक ऊपरी विरासत के रूप में माना जा सकता है: किसी भी सुपरपाइप को अनुमति दी जाती है और निर्दिष्ट प्रकार सहित:

class AutoColorComparer implements Comparator<Automobile>
    public int compare(Automobile a, Automobile b) {
        // Return comparison of colors
    }

इसका उपयोग कलेक्शन.सोर्ट के साथ किया जा सकता है :

public static <T> void sort(List<T> list, Comparator<? super T> c)

// Which you can call like this, without errors:
List<Car> cars = getListFromSomewhere();
Collections.sort(cars, new AutoColorComparer());

आप इसे एक तुलनित्र के साथ भी कह सकते हैं जो वस्तुओं की तुलना करता है और किसी भी प्रकार के साथ इसका उपयोग करता है।

गर्भनिरोधक या सह-विचरण का उपयोग कब करें?

थोड़ा सा OT शायद, आपने नहीं पूछा, लेकिन यह आपके प्रश्न का उत्तर देने में मदद करता है। सामान्य तौर पर, जब आप कुछ प्राप्त करते हैं, तो सहसंयोजक का उपयोग करें और जब आप कुछ डालते हैं, तो विरोधाभासी का उपयोग करें। स्टैक ओवरफ्लो प्रश्न के उत्तर में यह सबसे अच्छी तरह से समझाया गया है कि जावा जेनरिक में कंट्रोवर्सी का उपयोग कैसे किया जाएगा?

तो फिर यह क्या है List<? extends Map<String, String>>

आप उपयोग करते हैं extends, इसलिए सहसंयोजक के लिए नियम लागू होते हैं। यहां आपके पास मानचित्रों की एक सूची है और सूची में आपके द्वारा संग्रहीत प्रत्येक आइटम एक Map<string, string>या उससे प्राप्त होना चाहिए । बयान List<Map<String, String>>से प्राप्त नहीं सकता Mapहै, लेकिन होना चाहिए एक Map

इसलिए, निम्नलिखित काम करेगा, क्योंकि TreeMapइनसे विरासत में मिली Map:

List<Map<String, String>> mapList = new ArrayList<Map<String, String>>();
mapList.add(new TreeMap<String, String>());

लेकिन यह नहीं होगा:

List<? extends Map<String, String>> mapList = new ArrayList<? extends Map<String, String>>();
mapList.add(new TreeMap<String, String>());

और यह या तो काम नहीं करेगा, क्योंकि यह सहसंयोजक बाधा को संतुष्ट नहीं करता है:

List<? extends Map<String, String>> mapList = new ArrayList<? extends Map<String, String>>();
mapList.add(new ArrayList<String>());   // This is NOT allowed, List does not implement Map

और क्या?

यह शायद स्पष्ट है, लेकिन आपने पहले ही नोट किया होगा कि extendsकीवर्ड का उपयोग केवल उस पैरामीटर पर लागू होता है, बाकी पर नहीं। यानी, निम्नलिखित संकलन नहीं करेगा:

List<? extends Map<String, String>> mapList = new List<? extends Map<String, String>>();
mapList.add(new TreeMap<String, Element>())  // This is NOT allowed

मान लीजिए आप स्ट्रिंग के रूप में एक कुंजी के साथ नक्शे में किसी भी प्रकार की अनुमति देना चाहते हैं, तो आप extendप्रत्येक प्रकार के पैरामीटर पर उपयोग कर सकते हैं । यानी, मान लीजिए कि आप XML प्रोसेस करते हैं और आप AttrNode, Element आदि को मैप में स्टोर करना चाहते हैं, तो आप कुछ ऐसा कर सकते हैं:

List<? extends Map<String, ? extends Node>> listOfMapsOfNodes = new...;

// Now you can do:
listOfMapsOfNodes.add(new TreeMap<Sting, Element>());
listOfMapsOfNodes.add(new TreeMap<Sting, CDATASection>());

कुछ भी नहीं "तो यह क्या है ... के साथ" संकलन करेगा।
नोबल अपलिफ्ट

@ नोबलअपलिफ्ट: यदि आपको मिलने वाले त्रुटि संदेश की आपूर्ति नहीं होती है तो आपकी मदद करना कठिन है। एसओ पर एक नया सवाल पूछने के लिए, विकल्प के रूप में भी विचार करें, सफलता का बड़ा मौका। उपरोक्त कोड सिर्फ स्निपेट हैं, यह निर्भर करता है कि आपने इसे अपने परिदृश्य में लागू किया है।
हाबिल

मेरे पास कोई नया प्रश्न नहीं है, मेरे पास सुधार हैं। List<? extends Map<String, String>> mapList = new ArrayList<? extends Map<String, String>>(); mapList.add(new TreeMap<String, String>());में परिणाम found: ? extends java.util.Map<java.lang.String,java.lang.String> required: class or interface without boundsList<Map<String, String>> mapList = new ArrayList<Map<String, String>>(); mapList.add(new TreeMap<String, String>());अच्छी तरह से काम। अंतिम उदाहरण स्पष्ट रूप से सही है।
नोबल उत्थान

@ नोबल उत्थान: क्षमा करें, लंबे समय से यात्रा कर रहा है, जब मैं वापस आऊंगा तो ठीक कर दूंगा, और चमकती हुई त्रुटि को इंगित करने के लिए धन्यवाद! :)
हाबील

कोई बात नहीं, मुझे खुशी है कि इसे ठीक कर लिया जाएगा। यदि आप उन्हें अनुमोदित करना चाहते हैं तो मैंने आपके लिए संपादन किया है।
नोबल उत्थान

4

आज, मैंने इस सुविधा का उपयोग किया है, इसलिए यहां मेरा बहुत ताजा वास्तविक जीवन उदाहरण है। (मैंने सामान्य लोगों के वर्ग और विधि के नाम बदल दिए हैं ताकि वे वास्तविक बिंदु से विचलित न हों।)

मेरे पास एक ऐसा तरीका है जो Setउन Aवस्तुओं को स्वीकार करने के लिए है जिन्हें मैंने मूल रूप से इस हस्ताक्षर के साथ लिखा था:

void myMethod(Set<A> set)

लेकिन यह वास्तव में इसे Setउपवर्गों के साथ कॉल करना चाहता है A। लेकिन इसकी अनुमति नहीं है! (इसका कारण यह है कि myMethodवस्तुओं को setउस प्रकार से जोड़ सकते हैं A, लेकिन उप-प्रकार के नहींset ऑब्जेक्ट को कॉलर की साइट पर घोषित किया जाता है। इसलिए यह टाइप सिस्टम को तोड़ सकता है यदि यह संभव था।)

अब यहां बचाव के लिए जेनरिक आते हैं, क्योंकि यह इस तरीके से काम करता है जैसे कि मैं इस पद्धति के हस्ताक्षर का उपयोग करता हूं:

<T extends A> void myMethod(Set<T> set)

या कम, यदि आपको विधि बॉडी में वास्तविक प्रकार का उपयोग करने की आवश्यकता नहीं है:

void myMethod(Set<? extends A> set)

इस प्रकार, setप्रकार वास्तविक उपप्रकार की वस्तुओं का एक संग्रह बन जाता है A, इसलिए प्रकार प्रणाली को खतरे में डाले बिना उपवर्गों के साथ इसका उपयोग करना संभव हो जाता है।


0

जैसा कि आपने उल्लेख किया है, सूची को परिभाषित करने के दो निम्न संस्करण हो सकते हैं:

  1. List<? extends Map<String, String>>
  2. List<?>

2 बहुत खुला है। यह किसी भी वस्तु प्रकार को पकड़ सकता है। यह उस मामले में उपयोगी नहीं हो सकता है जब आप किसी दिए गए प्रकार का नक्शा चाहते हैं। यदि कोई व्यक्ति गलती से एक अलग प्रकार का मानचित्र बनाता है, उदाहरण के लिए,Map<String, int> ,। आपकी उपभोक्ता पद्धति टूट सकती है।

यह सुनिश्चित करने के लिए कि Listकिसी दिए गए प्रकार की वस्तुओं को धारण किया जा सकता है, जावा जेनरिक ने पेश किया ? extends। तो # 1 में, Listकिसी भी वस्तु को पकड़ सकता है जो कि Map<String, String>प्रकार से ली गई है । किसी अन्य प्रकार के डेटा को जोड़ने से एक अपवाद होगा।

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