मैं सूची में कैसे जोड़ सकता हूं <? नंबर> डेटा संरचनाओं का विस्तार?


154

मेरे पास एक सूची है जो इस तरह से घोषित की गई है:

 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)

61
ध्यान दें कि List<? extends Number>"विभिन्न प्रकारों की वस्तुओं की सूची, जिसका सभी विस्तार करते हैं Number" का अर्थ नहीं है । इसका अर्थ है " एकल प्रकार की वस्तुओं की सूची जो फैली हुई है Number"।
पावेल मिनाएव

1
आप बेहतर पीईसीएस नियम की जांच करते हैं, निर्माता विस्तार करता है, उपभोक्ता सुपर। stackoverflow.com/questions/2723397/…
noego

जवाबों:


303

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

वाइल्डकार्ड घोषणा का 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क्योंकि foo3एक पर इंगित किया जा सकता है List<Double>
  • आप जोड़ नहीं सकते Doubleक्योंकि foo3एक पर इंगित किया जा सकता है List<Integer>
  • आप जोड़ नहीं सकते Numberक्योंकि foo3एक पर इंगित किया जा सकता है List<Integer>

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

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


इसका आदर्श उदाहरण निम्नलिखित है Collections.copy():

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

ध्यान दें कि srcसूची घोषणा का उपयोग किस प्रकार extendsमुझे संबंधित सूची प्रकारों के परिवार से किसी भी सूची को पारित करने की अनुमति देता है और फिर भी यह गारंटी देता है कि यह T के प्रकार T या उपवर्गों के मूल्यों का उत्पादन करेगा। लेकिन आप 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>

11
हमें 'लिस्ट <जैसे वाक्य लिखने की अनुमति क्यों है? फैली संख्या> foo3 = नया एरियरिस्ट <Integer> (); `अगर हम इस सूची में एक तत्व को आगे नहीं बढ़ा सकते हैं?
अमित कुमार गुप्ता

7
@ कार्टिक्लसैक: किसी सूची के साथ काम करना एकमात्र उपयोगी चीज नहीं है। एक सूची के पॉप्युलेट होने के बाद, किसी सूची से पढ़ना उपयोगी हो सकता है। सामान्य वाइल्डकार्ड्स कोड लिखने की अनुमति देता है जो सूची के एक परिवार के लिए उदारता से काम करता है, उदाहरण के लिए सूची <Integer> या List / Double> दोनों के लिए काम करता है। उदाहरण के लिए, Collection.copy () के हस्ताक्षर को देखें। src Listतर्क का उपयोग करता है extendssrc सूची से पढ़ने के लिए है, जबकि dest Listतर्क का उपयोग करता है superगंतव्य सूची में लिखने के लिए। यह एक विधि है कि से कॉपी कर सकते हैं अनुमति देता है List<Integer>या List<Double>में List<Number>या List<Object>
बर्ट F

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

हाँ, मैंने इसे भी देखा @Vortex Im यकीन नहीं है कि यह सही है या मैंने इसे गलत पढ़ा है।
1922 में

1
@ वोर्टेक्स - or subclass of Tसही है। उदाहरण के लिए, मैं एक Object(सुपरक्लास का Number) जोड़ नहीं सकता List<? super Number> foo3क्योंकि foo3इसे सौंपा गया है: List<? super Number> foo3 = new ArrayList<Number>(जिसमें केवल Numberया उपवर्ग हो सकते हैं Number)। एस <? super Number>के प्रकारों को संदर्भित करता है जिन्हें List<>सौंपा जा सकता है foo3- उन चीजों के प्रकार नहीं जिन्हें इससे जोड़ा / पढ़ा जा सकता है। जिन चीज़ों को जोड़ा / हटाया foo3जा सकता है, वे ऐसी चीज़ें होनी चाहिए जिन्हें किसी भी तरह से जोड़ा / हटाया List<>जा सकता है foo3
बर्ट एफ

17

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

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

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


2

"सूची" <'; फैली हुई संख्या> वास्तव में एक ऊपरी बाध्य वाइल्डकार्ड है!

ऊपरी-सीमा वाले वाइल्डकार्ड का कहना है कि किसी भी वर्ग जो संख्या या संख्या का विस्तार करता है, को औपचारिक पैरामीटर प्रकार के रूप में उपयोग किया जा सकता है: समस्या इस तथ्य से उपजी है कि जावा को नहीं पता है कि वास्तव में किस प्रकार की सूची है। यह एक प्रकार का और अद्वितीय प्रकार होना चाहिए। मुझे उम्मीद है यह मदद करेगा :)


2

भले ही मुझे पावेल मिनेव की टिप्पणी मिली हो, जब तक मैंने यहां जवाब नहीं पढ़ा, तब भी यह मुझे भ्रमित कर रहा है:

ध्यान दें कि सूची <? विस्तार संख्या> का अर्थ "विभिन्न प्रकारों की वस्तुओं की सूची नहीं है, जो सभी संख्या का विस्तार करते हैं"। इसका अर्थ है "एकल प्रकार की वस्तुओं की सूची जो संख्या का विस्तार करती है"

इसके बाद मैं BertF की भयानक व्याख्या को समझने में सक्षम हुआ। सूची <? फैली संख्या> का मतलब है? किसी भी प्रकार की संख्या हो सकती है (नंबर, डबल, आदि) और इसकी घोषणा में स्पष्ट नहीं किया गया है (सूची -। नंबर 1> सूची का विस्तार करता है) कि उनमें से कौन सा है, इसलिए जब यू एड का उपयोग विधि इसकी ज्ञात नहीं है अगर इनपुट है उसी प्रकार का या नहीं; प्रकार क्या है?

तो सूची के तत्व <? विस्तार> निर्माण के समय केवल सेट किया जा सकता है।

यह भी ध्यान दें: जब हम टेम्पलेट्स का उपयोग कर रहे हैं तो हम संकलक को बता रहे हैं कि हम किस प्रकार के साथ खिलवाड़ कर रहे हैं। उदाहरण के लिए T हमारे लिए उस प्रकार का है, लेकिन नहीं ? वही करता है

मुझे कहना होगा .. यह समझाने / जानने के लिए गंदे लोगों में से एक है



0

आप एक अलग प्रकार के साथ सूची का संदर्भ बनाकर इसे ठग सकते हैं।

(ये sepp2k द्वारा उल्लिखित "असुरक्षित जाति" हैं।)

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

// This will not compile
//list.add(100);

// WORKS, BUT NOT IDEAL
List untypedList = (List)list;
// It will let you add a number
untypedList.add(200);
// But it will also let you add a String!  BAD!
untypedList.add("foo");

// YOU PROBABLY WANT THIS
// This is safer, because it will (partially) check the type of anything you add
List<Number> superclassedList = (List<Number>)(List<?>)list;
// It will let you add an integer
superclassedList.add(200);
// It won't let you add a String
//superclassedList.add("foo");
// But it will let you add a Float, which isn't really correct
superclassedList.add(3.141);
// ********************
// So you are responsible for ensuring you only add/set Integers when you have
// been given an ArrayList<Integer>
// ********************

// EVEN BETTER
// If you can, if you know the type, then use List<Integer> instead of List<Number>
List<Integer> trulyclassedList = (List<Integer>)(List<?>)list;
// That will prevent you from adding a Float
//trulyclassedList.add(3.141);

System.out.println("list: " + list);

क्योंकि untypedList, superclassedListऔर trulyclassedListसिर्फ संदर्भ हैं list, आप अभी भी मूल एरेलेस्ट में तत्वों को जोड़ रहे हैं।

आपको वास्तव (List<?>)में ऊपर दिए गए उदाहरण में उपयोग करने की आवश्यकता नहीं है, लेकिन आपको अपने कोड में इसकी आवश्यकता हो सकती है, जो listआपके द्वारा दिए गए प्रकार पर निर्भर करता है ।

ध्यान दें कि उपयोग करने ?से आपको कंपाइलर चेतावनी मिलेगी, जब तक आप इसे अपने फ़ंक्शन के ऊपर नहीं डालते हैं:

@SuppressWarnings("unchecked")

-1

जहां 'ऑब्जेक्ट' से सूची का विस्तार करें, आप सूची का उपयोग कर सकते हैं। एड और जब आप सूची का उपयोग करना चाहते हैं। केवल अपने ऑब्जेक्ट पर ऑब्जेक्ट डालने की आवश्यकता है;

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