2010-05-05 9 views
108

मेरे पास एक सूची है जिसे इस तरह घोषित किया गया है:मैं सूची में कैसे जोड़ सकता हूं <? संख्या> डेटा संरचनाओं का विस्तार करता है?

 List<? extends Number> foo3 = new ArrayList<Integer>(); 

मैंने foo3 में 3 जोड़ने की कोशिश की। हालांकि मुझे इस तरह एक त्रुटि संदेश मिलता है:

The method add(capture#1-of ? extends Number) in the type List<capture#1-of ? 
extends Number> is not applicable for the arguments (ExtendsNumber) 
+43

ध्यान दें कि 'सूची

+1

Google 'रूपांतरण कैप्चर करें'। –

+1

आप बेहतर पीईसीएस नियम, निर्माता विस्तार, उपभोक्ता सुपर की जांच करते हैं। http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super – noego

उत्तर

225

क्षमा करें, लेकिन आप नहीं कर सकते।

List<? extends Number> foo3 की वाइल्डकार्ड घोषणा का मतलब है कि चर foo3 एक (एक विशेष प्रकार के किसी भी मूल्य के बजाय) प्रकार के परिवार से किसी भी मान हो सकता है। इसका मतलब है कि इनमें से किसी भी कानूनी कार्य कर रहे हैं:

  • :

    List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number 
    List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number 
    List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number 
    

    तो, यह, वस्तु की आप किस प्रकार List foo3 को जोड़ सकता है यह देखते हुए कि इसके बाद के संस्करण संभव ArrayList कार्य से किसी के बाद कानूनी होगा आप Integer नहीं जोड़ सकते क्योंकि foo3List<Double> पर इंगित कर सकता है।

  • आप क्योंकि foo3 एक Double एक List<Integer> पर इशारा करते हुए किया जा सकता है नहीं जोड़ सकते।
  • आप Number नहीं जोड़ सकते हैं क्योंकि foo3List<Integer> पर इंगित कर सकता है।

आप क्योंकि आप गारंटी नहीं दे सकते List किस तरह यह वास्तव में की ओर इशारा करते है List<? extends T> के लिए किसी भी वस्तु नहीं जोड़ सकते, तो आप गारंटी नहीं दे सकते कि उद्देश्य यह है कि List में अनुमति दी है। केवल "गारंटी" यह है कि आप केवल इससे पढ़ सकते हैं और आपको T या T के उप-वर्ग प्राप्त होंगे।

रिवर्स तर्क super पर लागू होता है, उदा। List<? super T>। ये कानूनी हैं:

List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number 
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number 

आप List<? super T> से विशेष प्रकार टी (जैसे Number) क्योंकि आप गारंटी नहीं दे सकते List किस तरह यह वास्तव में की ओर इशारा करते है नहीं पढ़ सकता। आपके पास केवल "गारंटी" है, आप इस सूची की अखंडता का उल्लंघन किए बिना T (या T के किसी उप-वर्ग) का मान जोड़ने में सक्षम हैं।

public static <T> void copy(List<? super T> dest,List<? extends T> src) 

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


इस का आदर्श उदाहरण Collections.copy() के लिए हस्ताक्षर है गारंटी है कि यह टी के प्रकार या टी के उप-वर्गों के मूल्यों का उत्पादन करेगा। लेकिन आप src सूची में नहीं जोड़ सकते हैं।

dest सूची घोषणा super का उपयोग करती है ताकि मुझे संबंधित सूची प्रकारों के किसी परिवार से किसी भी सूची को पास करने की अनुमति मिल सके और फिर भी गारंटी हो कि मैं उस सूची में किसी विशिष्ट प्रकार टी का मान लिख सकता हूं। लेकिन अगर मैं सूची से पढ़ता हूं तो विशिष्ट टाइप टी के मानों को पढ़ने की गारंटी नहीं दी जा सकती है।

तो अब, जेनरिक वाइल्डकार्ड के लिए धन्यवाद, मुझे लगता है कि एक विधि के साथ इन कॉल के किसी भी कर सकते हैं:

// copy(dest, src) 
Collections.copy(new ArrayList<Number>(), new ArrayList<Number()); 
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer()); 
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>()); 
Collections.copy(new ArrayList<Object>(), new ArrayList<Double()); 

अपने दिमाग व्यायाम करने के लिए इस भ्रामक और बहुत व्यापक कोड पर विचार करें। टिप्पणी की गई लाइनें अवैध हैं और लाइन के चरम दाएं कोने का कारण बताया गया है (उनमें से कुछ को देखने के लिए स्क्रॉल करने की आवश्यकता है):

List<Number> listNumber_ListNumber = new ArrayList<Number>(); 
//List<Number> listNumber_ListInteger = new ArrayList<Integer>();     // error - can assign only exactly <Number> 
//List<Number> listNumber_ListDouble = new ArrayList<Double>();      // error - can assign only exactly <Number> 

    List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>(); 
    List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>(); 
    List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>(); 

    List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>(); 
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>();  // error - Integer is not superclass of Number 
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>();  // error - Double is not superclass of Number 


//List<Integer> listInteger_ListNumber = new ArrayList<Number>();     // error - can assign only exactly <Integer> 
    List<Integer> listInteger_ListInteger = new ArrayList<Integer>(); 
//List<Integer> listInteger_ListDouble = new ArrayList<Double>();     // error - can assign only exactly <Integer> 

//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer 
    List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>(); 
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer 

    List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>(); 
    List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>(); 
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>();  // error - Double is not a superclass of Integer 


    listNumber_ListNumber.add(3);    // ok - allowed to add Integer to exactly List<Number> 

    // These next 3 are compile errors for the same reason: 
    // You don't know what kind of List<T> is really 
    // being referenced - it may not be able to hold an Integer. 
    // You can't add anything (not Object, Number, Integer, 
    // nor Double) to List<? extends Number>  
//listExtendsNumber_ListNumber.add(3);  // error - can't add Integer to *possible* List<Double>, even though it is really List<Number> 
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer> 
//listExtendsNumber_ListDouble.add(3);  // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double> 

    listSuperNumber_ListNumber.add(3);  // ok - allowed to add Integer to List<Number> or List<Object> 

    listInteger_ListInteger.add(3);   // ok - allowed to add Integer to exactly List<Integer> (duh) 

    // This fails for same reason above - you can't 
    // guarantee what kind of List the var is really 
    // pointing to 
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's 

    listSuperInteger_ListNumber.add(3);  // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object> 
    listSuperInteger_ListInteger.add(3);  // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object> 
+6

हमें 'सूची <' जैसी वाक्य लिखने की अनुमति क्यों है? संख्या> foo3 = new ArrayList (); 'अगर हम इस सूची में कोई तत्व नहीं दे सकते हैं? –

+6

@articlestack: जोड़ना एक सूची के साथ एकमात्र उपयोगी बात नहीं है। एक बार सूची पॉप्युलेट हो जाने पर, सूची से पढ़ना उपयोगी हो सकता है। जेनेरिक वाइल्डकार्ड कोड लिखने की अनुमति देता है जो सूचियों के परिवार के लिए सामान्य रूप से काम करता है, उदाहरण के लिए सूची या सूची दोनों के लिए काम करता है। उदाहरण के लिए, Collection.copy() के हस्ताक्षर को देखें। 'Src'' list' तर्क src सूची से पढ़ने के लिए 'विस्तार' का उपयोग करता है, जबकि 'dest'' list' तर्क dest सूची में लिखने के लिए 'super' का उपयोग करता है। यह एक विधि की अनुमति देता है जो 'सूची ' या 'सूची ' से 'सूची ' या 'सूची ' में कॉपी कर सकती है। –

+0

बर्ट एफ, देर से टिप्पणी के लिए खेद है। क्या आपके मार्ग में एक टाइपो है, "टाइप टी (या टी के उप-वर्ग) का मूल्य जोड़ने के लिए (या टी का सुपरक्लास) पढ़ना चाहिए? – Vortex

13

आप (असुरक्षित जानवरों के बिना) नहीं कर सकते हैं। आप केवल उनसे पढ़ सकते हैं।

समस्या यह है कि आप नहीं जानते कि सूची वास्तव में सूची क्या है। यह संख्या के किसी भी उप-वर्ग की एक सूची हो सकती है, इसलिए जब आप इसमें कोई तत्व डालने का प्रयास करते हैं, तो आप नहीं जानते कि तत्व वास्तव में सूची में फिट बैठता है।

उदाहरण के लिए सूची Byte एस की एक सूची हो सकती है, इसलिए इसमें Float डालने में त्रुटि होगी।

2

आप इस के बजाय कर सकता है:

List<Number> foo3 = new ArrayList<Number>();  
    foo3.add(3); 
संबंधित मुद्दे

 संबंधित मुद्दे