दिलचस्प पोस्ट
आईफ़ोन अनज़िप कोड अच्छा PHP ORM लाइब्रेरी? गेम स्टेट को बचाने का सबसे अच्छा तरीका क्या है? प्राइमरी कुंजी के रूप में एक GUID का उपयोग करने के लिए सबसे अच्छा अभ्यास क्या हैं, विशेष रूप से प्रदर्शन के बारे में? क्विकोोर्ट: धुरी का चयन eof () बुरा अभ्यास? तुलना () और तुलना () के बीच अंतर क्या है? स्क्रीन चौड़ाई और ऊंचाई प्राप्त करें निकालें और जार से डीएलएल लोड एसटीडी :: गेटलाइन () एक फॉर्मेटेड निष्कर्षण के बाद इनपुट को छोड़ क्यों देता है? एजेएक्स एमवीसी के माध्यम से एक्सेल फाइल डाउनलोड करें PHP: एक सरणी में दो तिथियों के बीच सभी तिथियां लौटें मोंगोडब समूह मान कई क्षेत्रों के द्वारा मूल्य Javafx टेबलव्यूले सभी कॉलम में डेटा नहीं दिखा रहा है सूची रिटर्न के साथ पायथन पुनरावर्तन कोई नहीं

<में अंतर क्या है <? सुपर ई> और <? ई विस्तारित?

<? super E> में अंतर क्या है <? super E> <? super E> और <? extends E> <? extends E> ?

उदाहरण के लिए जब आप वर्ग java.util.concurrent.LinkedBlockingQueue पर एक नज़र डालते हैं, तो निर्माता के लिए निम्न हस्ताक्षर हैं:

 public LinkedBlockingQueue(Collection<? extends E> c) 

और विधि के लिए एक के लिए:

 public int drainTo(Collection<? super E> c) 

वेब के समाधान से एकत्रित समाधान "<में अंतर क्या है <? सुपर ई> और <? ई विस्तारित?"

पहले कहते हैं कि यह "कुछ प्रकार है जो ई का पूर्वज है"; दूसरा कहता है कि यह "कुछ प्रकार है जो ई के उप-वर्ग है" (दोनों ही मामलों में ई खुद ठीक है।)

तो निर्माता का उपयोग करता है ? extends E ? extends E फॉर्म का ? extends E है इसलिए यह गारंटी देता है कि जब वह संग्रह से मूल्य प्राप्त करता है, तो वे सभी ई या कुछ उप-वर्ग होंगे (यानी यह संगत है)। drainTo विधि संग्रह में मूल्यों को रखने का प्रयास कर रही है, इसलिए संग्रह में एक तत्व प्रकार E या सुपरक्लास होना चाहिए

एक उदाहरण के रूप में, मान लीजिए आपके पास इस तरह की एक श्रेणी पदानुक्रम है:

 Parent extends Object Child extends Parent 

और एक LinkedBlockingQueue<Parent> आप एक List<Child> में इस गुजरने का निर्माण कर सकते हैं, जो सभी तत्वों को सुरक्षित रूप से प्रतिलिपि करेंगे, क्योंकि हर Child को माता-पिता होता है आप एक List<Object> नहीं जा सकी क्योंकि कुछ तत्व Parent के साथ संगत नहीं हैं।

इसी तरह आप उस कतार को एक List<Object> में हटा सकते हैं क्योंकि हर Parent एक Object … लेकिन आप इसे List<Child> में नहीं हटा सकते क्योंकि List<Child> को उसके सभी तत्वों को Child के साथ संगत होना चाहिए।

इसका कारण यह है कि कैसे जावा जेनेरिक का कार्यान्वयन करता है।

एक एरेज़ उदाहरण

सरणियों के साथ आप यह कर सकते हैं (arrays covariant हैं)

 Integer[] myInts = {1,2,3,4}; Number[] myNumber = myInts; 

लेकिन, अगर आप ऐसा करने की कोशिश करेंगे तो क्या होगा?

 myNumber[0] = 3.14; //attempt of heap pollution 

यह अंतिम पंक्ति सिर्फ ठीक संकलित होगी, लेकिन यदि आप इस कोड को चलाते हैं, तो आप एक ArrayStoreException प्राप्त कर सकते हैं। क्योंकि आप एक पूर्णांक सरणी में एक दोहरी डाल करने की कोशिश कर रहे हैं (चाहे किसी संख्या संदर्भ के माध्यम से पहुंचा जा रहा हो)।

इसका मतलब यह है कि आप संकलक को बेवकूफ़ बना सकते हैं, लेकिन आप रनटाइम टाइप सिस्टम को बेवकूफ़ नहीं बना सकते। और ऐसा इसलिए है क्योंकि सरणियां वे हैं जो हम प्रत्याशित प्रकार कहते हैं । इसका मतलब यह है कि जावा पर चलने वाले समय के बारे में जानता है कि यह सरणी वास्तव में इंटिजर्स की एक सरणी के रूप में शुरू की गई थी, जो कि टाइप Number[] संदर्भ के माध्यम से पहुंचा जा सकती है।

तो, जैसा कि आप देख सकते हैं, एक चीज वस्तु का वास्तविक प्रकार है, और दूसरी चीज वह संदर्भ है जिसे आप इसे एक्सेस करने के लिए उपयोग करते हैं, है ना?

जावा जेनेरिक्स के साथ समस्या

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

लेकिन यहां एक महत्वपूर्ण मुद्दा यह है कि चूंकि रनटाइम में कोई प्रकार की जानकारी नहीं है, इसलिए यह सुनिश्चित करने का कोई रास्ता नहीं है कि हम ढेर प्रदूषण नहीं कर रहे हैं।

उदाहरण के लिए,

 List<Integer> myInts = new ArrayList<Integer>(); myInts.add(1); myInts.add(2); List<Number> myNums = myInts; //compiler error myNums.add(3.14); //heap pollution 

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

जैसे, जावा के डिजाइनर ने सुनिश्चित किया कि आप संकलक को बेवकूफ़ नहीं बना सकते। यदि आप कंपाइलर को बेवकूफ़ नहीं बना सकते (जैसा कि हम सरणियों के साथ कर सकते हैं) आप रनटाइम टाइप सिस्टम को भी बेवकूफ़ नहीं बना सकते हैं

जैसे, हम कहते हैं कि सामान्य प्रकार गैर-पुनर्निर्मित हैं

जाहिर है, यह बहुरूपता को बाधित करेगा निम्नलिखित उदाहरण पर विचार करें:

 static long sum(Number[] numbers) { long summation = 0; for(Number number : numbers) { summation += number.longValue(); } return summation; } 

अब आप इसे इस तरह इस्तेमाल कर सकते हैं:

 Integer[] myInts = {1,2,3,4,5}; Long[] myLongs = {1L, 2L, 3L, 4L, 5L}; Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0}; System.out.println(sum(myInts)); System.out.println(sum(myLongs)); System.out.println(sum(myDoubles)); 

लेकिन अगर आप सामान्य संग्रह के साथ एक ही कोड को लागू करने का प्रयास करते हैं, तो आप सफल नहीं होंगे:

 static long sum(List<Number> numbers) { long summation = 0; for(Number number : numbers) { summation += number.longValue(); } return summation; } 

यदि आप कोशिश करते हैं तो आप संकलक ईआरओओ प्राप्त करेंगे …

 List<Integer> myInts = asList(1,2,3,4,5); List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L); List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0); System.out.println(sum(myInts)); //compiler error System.out.println(sum(myLongs)); //compiler error System.out.println(sum(myDoubles)); //compiler error 

समाधान जावा जेनेरिक के दो शक्तिशाली सुविधाओं का उपयोग करना सीखना है जिसे ज्ञानी और उल्लसित रूप में जाना जाता है।

सहप्रसरण

सहानुभूति के साथ आप एक संरचना से आइटम पढ़ सकते हैं, लेकिन आप इसमें कुछ भी नहीं लिख सकते। ये सभी मान्य घोषणाएं हैं।

 List<? extends Number> myNums = new ArrayList<Integer>(); List<? extends Number> myNums = new ArrayList<Float>(); List<? extends Number> myNums = new ArrayList<Double>(); 

और आप myNums से पढ़ सकते हैं:

 Number n = myNums.get(0); 

क्योंकि आप यह सुनिश्चित कर सकते हैं कि वास्तविक सूची में जो कुछ भी होता है, उसे एक नंबर पर बढ़ाया जा सकता है (संख्या के विस्तार के बाद जो संख्या है वह एक संख्या है, है ना?)

हालांकि, आपको किसी भी प्रकार की संरचना में डाल करने की अनुमति नहीं है।

 myNumst.add(45L); //compiler error 

इसकी अनुमति नहीं दी जाएगी, क्योंकि जावा गारंटी नहीं दे सकता कि जेनेरिक संरचना में वस्तु का वास्तविक प्रकार क्या है। यह कुछ भी हो सकता है जो संख्या बढ़ाता है, लेकिन संकलक सुनिश्चित नहीं हो सकता। तो आप पढ़ सकते हैं, लेकिन लिख नहीं सकते

contravariance

भ्रष्टता के साथ आप विपरीत कार्य कर सकते हैं। आप चीजों को एक सामान्य संरचना में रख सकते हैं, लेकिन आप इससे बाहर नहीं पढ़ सकते हैं।

 List<Object> myObjs = new List<Object>(); myObjs.add("Luke"); myObjs.add("Obi-wan"); List<? super Number> myNums = myObjs; myNums.add(10); myNums.add(3.14); 

इस मामले में, ऑब्जेक्ट की वास्तविक प्रकृति ऑब्जेक्ट्स की एक सूची है, और भ्रांति के माध्यम से, आप इसमें नंबर डाल सकते हैं, मूलतः क्योंकि सभी नंबरों को ऑब्जेक्ट उनके सामान्य पूर्वज के रूप में है। जैसे, सभी नंबर वस्तुएं हैं, और इसलिए यह मान्य है

हालांकि, आप इस पोषक तत्व संरचना से कुछ भी सुरक्षित रूप से नहीं पढ़ सकते हैं, यह मानते हुए कि आपको एक संख्या मिल जाएगी।

 Number myNum = myNums.get(0); //compiler-error 

जैसा कि आप देख सकते हैं, यदि कंपाइलर ने आपको यह पंक्ति लिखने की अनुमति दी है, तो आपको रनटाइम पर क्लाससेलस्ट एक्सपैशन मिलेगा।

सिद्धांत प्राप्त करें / रखो

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

मेरे पास सबसे अच्छा उदाहरण निम्न है जो एक सूची से किसी भी सूची की दूसरी सूची में कॉपी करता है। यह केवल स्रोत से आइटम प्राप्त करता है, और यह केवल भाग्य में आइटम डालता है

 public static void copy(List<? extends Number> source, List<? super Number> destiny) { for(Number number : source) { destiny.add(number); } } 

सहानुभूति की शक्तियों के प्रति धन्यवाद और इस तरह के मामलों के लिए इस काम को बदनाम करें:

 List<Integer> myInts = asList(1,2,3,4); List<Double> myDoubles = asList(3.14, 6.28); List<Object> myObjs = new ArrayList<Object>(); copy(myInts, myObjs); copy(myDoubles, myObjs); 

<? extends E> <? extends E> करता है E ऊपरी बाध्य के रूप में E परिभाषित करता है: "इसे E डाला जा सकता है"

<? super E> <? super E> निचले बाउंड के रूप में E परिभाषित करता है: " E को इस पर डाला जा सकता है।"

मैं कोशिश करूँगा और इसका उत्तर दूंगा। लेकिन वास्तव में अच्छा जवाब पाने के लिए आपको जोजो ब्लाच की पुस्तक प्रभावी जावा (2 संस्करण) की जांच करनी चाहिए। वह स्मरक पीईसीएस का वर्णन करता है, जो "निर्माता विस्तार, उपभोक्ता सुपर" के लिए खड़ा है

विचार यह है कि यदि आप कोड वस्तु से जेनेरिक मानों का उपभोग कर रहे हैं, तो आपको विस्तार का उपयोग करना चाहिए। लेकिन यदि आप जेनेरिक प्रकार के लिए नए मान पैदा कर रहे हैं तो आपको सुपर उपयोग करना चाहिए

उदाहरण के लिए:

 public void pushAll(Iterable<? extends E> src) { for (E e: src) push(e); } 

तथा

 public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()) } 

लेकिन वास्तव में आपको इस पुस्तक की जांच करनी चाहिए: http://java.sun.com/docs/books/effective/

हो सकता है कि आप नियमों के लिए भौगोलिक स्थिति ( <? super E> ) और सहानुभूति ( <? extends E> ) के लिए Google चाहें । मैंने पाया है कि जेनेरिक समझने के लिए सबसे उपयोगी चीज मेरे लिए Collection.addAll के विधि हस्ताक्षर को समझने के लिए थी। Add all:

 public interface Collection<T> { public boolean addAll(Collection<? extends T> c); } 

जैसे आप एक String को एक List<Object> जोड़ना चाहते हैं, जैसे:

 List<Object> lo = ... lo.add("Hello") 

आप addAll विधि के माध्यम से एक List<String> (या String किसी भी संग्रह) को जोड़ने में सक्षम होना चाहिए:

 List<String> ls = ... lo.addAll(ls) 

हालाँकि आपको यह पता होना चाहिए कि एक List<Object> और एक List<String> समान नहीं है और न ही पूर्व में इसका उपवर्ग है क्या जरूरत है एक संप्रदाय प्रकार पैरामीटर की अवधारणा – यानी <? extends T> <? extends T>

एक बार आपके पास यह है, परिदृश्यों के बारे में सोचना आसान है, जहां पर आप भ्रष्टाचार चाहते हैं ( Comparable अंतरफलक देखें)।

<? super E> <? super E> अर्थ any object including E that is parent of E

<? extends E> <? extends E> अर्थात् any object including E that is child of E .

ऊपरी बाउंड के साथ एक वाइल्डकार्ड "? विस्तार प्रकार" जैसा दिखता है और सभी प्रकार के परिवार के लिए खड़ा है, जो प्रकार के प्रकार, टाइप प्रकार शामिल हैं। प्रकार ऊपरी बाउंड कहा जाता है।

निचली बाउंड के साथ एक वाइल्डकार्ड "सुपर टाइप" जैसा दिखता है और सभी प्रकार के परिवार के लिए खड़ा है, जो कि प्रकार के सुपरस्टेप हैं, प्रकार टाइप किया जा रहा है प्रकार को निचला बाउंड कहा जाता है।

उत्तर से पहले; कृपया यह स्पष्ट हो कि

  1. जेनरिक केवल समय की सुविधा को संकलित करके TYPE_SAFETY को सुनिश्चित करते हैं, यह RUNTIME के ​​दौरान उपलब्ध नहीं होता।
  2. केवल जेनरिक के साथ एक संदर्भ टाइप सुरक्षा को मजबूर कर देगा; अगर संदर्भ जेनेरिक के साथ घोषित नहीं किया जाता है तो यह बिना किसी प्रकार की सुरक्षा के काम करेगा

उदाहरण:

 List stringList = new ArrayList<String>(); stringList.add(new Integer(10)); // will be successful. 

आशा है कि यह आपको वाइल्डकार्ड को और अधिक स्पष्ट समझने में मदद करेगा।

 //NOTE CE - Compilation Error // 4 - For class A {} class B extends A {} public class Test { public static void main(String args[]) { A aObj = new A(); B bObj = new B(); //We can add object of same type (A) or its subType is legal List<A> list_A = new ArrayList<A>(); list_A.add(aObj); list_A.add(bObj); // A aObj = new B(); //Valid //list_A.add(new String()); Compilation error (CE); //can't add other type A aObj != new String(); //We can add object of same type (B) or its subType is legal List<B> list_B = new ArrayList<B>(); //list_B.add(aObj); CE; can't add super type obj to subclass reference //Above is wrong similar like B bObj = new A(); which is wrong list_B.add(bObj); //Wild card (?) must only come for the reference (left side) //Both the below are wrong; //List<? super A> wildCard_Wrongly_Used = new ArrayList<? super A>(); //List<? extends A> wildCard_Wrongly_Used = new ArrayList<? extends A>(); //Both <? extends A>; and <? super A> reference will accept = new ArrayList<A> List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<A>(); list_4__A_AND_SuperClass_A = new ArrayList<Object>(); //list_4_A_AND_SuperClass_A = new ArrayList<B>(); CE B is SubClass of A //list_4_A_AND_SuperClass_A = new ArrayList<String>(); CE String is not super of A List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<A>(); list_4__A_AND_SubClass_A = new ArrayList<B>(); //list_4__A_AND_SubClass_A = new ArrayList<Object>(); CE Object is SuperClass of A //CE; super reference, only accepts list of A or its super classes. //List<? super A> list_4__A_AND_SuperClass_A = new ArrayList<String>(); //CE; extends reference, only accepts list of A or its sub classes. //List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<Object>(); //With super keyword we can use the same reference to add objects //Any sub class object can be assigned to super class reference (A) list_4__A_AND_SuperClass_A.add(aObj); list_4__A_AND_SuperClass_A.add(bObj); // A aObj = new B(); //list_4__A_AND_SuperClass_A.add(new Object()); // A aObj != new Object(); //list_4__A_AND_SuperClass_A.add(new String()); CE can't add other type //We can't put anything into "? extends" structure. //list_4__A_AND_SubClass_A.add(aObj); compilation error //list_4__A_AND_SubClass_A.add(bObj); compilation error //list_4__A_AND_SubClass_A.add(""); compilation error //The Reason is below //List<Apple> apples = new ArrayList<Apple>(); //List<? extends Fruit> fruits = apples; //fruits.add(new Strawberry()); THIS IS WORNG :) //Use the ? extends wildcard if you need to retrieve object from a data structure. //Use the ? super wildcard if you need to put objects in a data structure. //If you need to do both things, don't use any wildcard. //Another Solution //We need a strong reference(without wild card) to add objects list_A = (ArrayList<A>) list_4__A_AND_SubClass_A; list_A.add(aObj); list_A.add(bObj); list_B = (List<B>) list_4__A_AND_SubClass_A; //list_B.add(aObj); compilation error list_B.add(bObj); private Map<Class<? extends Animal>, List<? extends Animal>> animalListMap; public void registerAnimal(Class<? extends Animal> animalClass, Animal animalObject) { if (animalListMap.containsKey(animalClass)) { //Append to the existing List /* The ? extends Animal is a wildcard bounded by the Animal class. So animalListMap.get(animalObject); could return a List<Donkey>, List<Mouse>, List<Pikachu>, assuming Donkey, Mouse, and Pikachu were all sub classes of Animal. However, with the wildcard, you are telling the compiler that you don't care what the actual type is as long as it is a sub type of Animal. */ //List<? extends Animal> animalList = animalListMap.get(animalObject); //animalList.add(animalObject); //Compilation Error because of List<? extends Animal> List<Animal> animalList = animalListMap.get(animalObject); animalList.add(animalObject); } } } }