2016-02-27 14 views
6

जावा जेनिक्स को समझने की कोशिश कर रहे एक और नौसिखिया। मैंने पाया कि सभी विषय मैंने पाया है, लेकिन मेरे पास अभी भी बहुत सारे प्रश्न हैं। तुम मुझे निम्नलिखित बातें समझाने कृपया सकते हैं:<? कक्षा> और <विस्तारित करता है? सुपर क्लास> जावा में - यह इस तरह से क्यों काम करता है?

  1. <? extends SomeClass> का मतलब है कि ? कि इस किसी भी प्रकार के केवल SomeClass का एक उपवर्ग हो सकता है, "किसी भी प्रकार के", और extends SomeClass साधन है। ठीक है, मैं दो प्राथमिक कक्षाओं लिखें:
abstract class Person { 
    private String name; 
    public Person(String name) { 
     this.name = name; 
    } 
} 

class Student extends Person { 
    public Student(String name) { 
     super(name); 
    } 
} 

कक्षा Student हमारे उदाहरण में ? हो जाएगा। ? extends Person, सटीक होने के लिए। तब मैं ArrayList करने के लिए नए छात्र जोड़ने की कोशिश कर रहा हूँ, कि, जैसा कि मैंने ऊपर लिखा से समझते हैं, सभी वर्गों, कि व्यक्ति का उपवर्गों हैं लागू होता है:

Student clarissa = new Student("Clarissa Starling"); 
List<? extends Person> list = new ArrayList<>(); 
list.add(clarissa); //Does not compile 

ग्रहण कहते हैं:

" विधि ऐड प्रकार सूची तर्क के लिए लागू नहीं है (विद्यार्थी) "

में (# 3-का कब्जा? व्यक्ति फैली) कैसे वर्ग Student लागू नहीं किया जा सकता जब हम सूची की घोषणा की, <? extends Person> द्वारा paramethrized, और Student बिल्कुल वर्ग Person फैली?

फिर भी, निम्नलिखित कोड:

List<? super Person> list = new ArrayList<>(); 
list.add(clarissa); 

compiles और अच्छी तरह से काम करता है (list.get(0), विधि println को पारित कर दिया, मुझे toString मंगलाचरण के सही परिणाम से पता चलता)। के रूप में मैं समझता हूँ, List<? super Person> का मतलब है कि मैं इस सूची में किसी भी प्रकार के पारित कर सकते हैं, कि हमारे Person वर्ग के लिए सुपर प्रकार है (हमारे मामले में यह केवल Object वर्ग है)। लेकिन हम देखते हैं कि, तर्क के विपरीत, हम अपने List<? super Person> पर सबक्लास छात्र को आसानी से जोड़ सकते हैं!

ठीक है, एक तरफ हमारी भावनाओं रखा, और देखते हैं, क्या हमारे संग्रह में Clarissa स्टार्लिंग के साथ हो सकता है। चलो हमारे वर्ग Student लेते हैं, और यह करने के लिए तरीकों की एक जोड़ी जोड़ें:

class Student extends Person { 
    private int grant; 
    public Student(String name) { 
     super(name); 
    } 

    public void setGrant(int grant) { 
     this.grant = grant; 
    } 

    public int getGrant() { 
     return this.grant; 
    } 

} 

फिर हम एक वस्तु, इस नए सिरे से कक्षा से instantiated (हमारे वस्तु "Clarissa", उदाहरण के लिए) List<? extends Person> के पास,। ऐसा करने का मतलब है, हम अपने सुपरक्लास के संग्रह में सबक्लास स्टोर कर सकते हैं। हो सकता है, मैं कुछ fundamenthal विचारों समझ में नहीं आता, लेकिन इस स्तर पर मैं अपने सुपर-क्लास का संग्रह और संदर्भ के बताए चर करने के लिए "Clarissa" विरोध करने के लिए उपवर्ग जोड़ने के बीच कोई अंतर नहीं दिख रहा है, व्यक्ति द्वारा लिखा गया। जब हम अपने सुपरक्लास वैरिएबल का उपयोग करते हैं, तो हम उनमें से किसी एक का इलाज करना चाहते हैं, तो हमारे पास अनावश्यक विधियों की वही कमी है। तो, क्यों List<? extends SomeClass> उसी तरह काम नहीं करता है, जिसमें List<? super SomeClass> इसके विपरीत काम करता है?

  1. मैं <T> (या <E>, या JLS के उचित हिस्से से किसी अन्य पत्र) और <?> के बीच fundamenthal अंतर समझ में नहीं आता।<T> और <?>टाइपधारक हैं, तो हमारे पास दो "कीवर्ड" क्यों हैं (यह प्रतीक कीवर्ड नहीं हैं, मैंने जावा शब्द में दोनों प्रतीकों के भारी अर्थ पर जोर देने के लिए इस शब्द का उपयोग किया है) उसी उद्देश्य के लिए? प्लेसहोल्डर T एक निश्चित प्रकार के लिए और स्थानों पर जहां हम वास्तविक प्रकार हम इस पर काम करने में सक्षम होने की जरूरत है पता करने की जरूरत में खड़ा -
+1

मान लीजिए कि आपके पास दो वर्ग 'छात्र' और 'शिक्षक' हैं जो 'व्यक्ति' को बढ़ाते हैं। अब, आपने एक सूची 'सूची <बनाई है? व्यक्ति को बढ़ाता है> और मान लीजिए कि आपने इसमें 'छात्र' जोड़ा है, तो आप कैसे सुनिश्चित होंगे कि 'list.get (0)' आपको केवल 'छात्र' वापस कर देगा, न कि 'शिक्षक'? इस अस्पष्टता को रोकने के लिए इसकी अनुमति नहीं है। – user2004685

+2

पढ़ें http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs –

+0

मुझे उम्मीद है कि, list.get (0) एक ऑब्जेक्ट वापस कर देगा, जिसे सुपरक्लास प्रकार में डाला जाएगा, और मैं ' superclass (व्यक्ति) में घोषित, केवल विधियों का आह्वान करने में सक्षम हो जाएगा। –

उत्तर

10

तरह से मैं इसे देख यह है। इसके विपरीत वाइल्डकार्ड ? का अर्थ किसी भी प्रकार का है और मुझे यह जानने की आवश्यकता नहीं होगी कि वह प्रकार क्या है। आप वाइल्डकार्ड को किसी भी तरह से सीमित करने के लिए extends और super सीमाओं का उपयोग कर सकते हैं लेकिन वास्तविक प्रकार प्राप्त करने का कोई तरीका नहीं है।

तो, यदि मेरे पास List<? extends MySuper> है तो मुझे यह पता है कि इसमें प्रत्येक वस्तु MySuper इंटरफ़ेस लागू करती है, और उस सूची में मौजूद सभी ऑब्जेक्ट एक ही प्रकार के होते हैं। मुझे नहीं पता कि वह प्रकार क्या है, केवल यह है कि यह MySuper का कुछ उप प्रकार है। इसका मतलब है कि मैं उस सूची से वस्तुओं को तब तक प्राप्त कर सकता हूं जब तक मुझे केवल MySuper इंटरफ़ेस का उपयोग करने की आवश्यकता हो। मैं क्या नहीं कर सकता वस्तुओं को सूची में रखना है क्योंकि मुझे नहीं पता कि यह किस प्रकार है - संकलक इसे अनुमति नहीं देगा क्योंकि यहां तक ​​कि यदि मेरे पास सही प्रकार का ऑब्जेक्ट होता है, तो यह नहीं हो सकता संकलन समय पर सुनिश्चित करें। इसलिए, संग्रह एक पठन-केवल संग्रह में है।

जब आपके पास List<? super MySuper> है तो तर्क अन्य तरीके से काम करता है। यहां हम कह रहे हैं कि संग्रह एक निश्चित प्रकार का है जो MySuper का सुपरटेप है। इसका मतलब है कि आप हमेशा MySuper ऑब्जेक्ट जोड़ सकते हैं। आप क्या नहीं कर सकते, क्योंकि आप वास्तविक प्रकार को नहीं जानते हैं, इससे वस्तुओं को पुनर्प्राप्त किया जाता है। तो अब आपको एक प्रकार का लेखन-संग्रह मिला है।

जहां आप 'मानक' जेनेरिक प्रकार पैरामीटर बनाम बाध्य वाइल्डकार्ड का उपयोग करते हैं, जहां मतभेदों का मूल्य स्पष्ट होना शुरू हो जाता है। मान लीजिए कि मेरे पास 3 कक्षा Person, Student और Teacher है, Person के आधार पर Student और Teacher विस्तारित है। एक एपीआई में आप एक विधि लिख सकते हैं जो Person का संग्रह लेता है और संग्रह में प्रत्येक आइटम के लिए कुछ करता है। यह ठीक है, लेकिन आप वास्तव में केवल यह मानते हैं कि संग्रह कुछ प्रकार का है जो Person इंटरफ़ेस के साथ संगत है - इसे List<Student> और List<Teacher> के साथ समान रूप से अच्छी तरह से काम करना चाहिए। आप इस

public void myMethod(List<Person> people) { 
    for (Person p: people) { 
     p.doThing(); 
    } 
} 

की तरह विधि को परिभाषित तो यह List<Student> या List<Teacher> नहीं ले सकते। तो, बजाय, आप इसे List<? extends Person> लेने के लिए परिभाषित करेगा ...

public void myMethod(List<? extends Person> people){ 
    for (Person p: people) { 
     p.doThing(); 
    } 
} 

आपको लगता है कि क्योंकि myMethod कभी नहीं सूची में जोड़ने की जरूरत है क्या कर सकते हैं। और अब आप पाते हैं कि List<Student> और List<Teacher> दोनों को विधि में पारित किया जा सकता है।

अब, मान लीजिए कि आपके पास एक और तरीका है जो छात्रों को सूची में जोड़ना चाहता है। यदि विधि पैरामीटर List<Student> लेता है तो यह List<People> नहीं ले सकता है, भले ही यह ठीक होना चाहिए। इसलिए, आप इसे List<? super Student> उदा।

public void listPopulatingMethod(List<? extends Student> source, List<? super Student> sink) { 
    for (Student s: source) { 
     sink.add(s); 
    } 
} 

यह पीईसीएस का दिल है, जिसे आप कहीं और अधिक विस्तार से पढ़ सकते हैं ... What is PECS (Producer Extends Consumer Super)? http://www.javacodegeeks.com/2011/04/java-generics-quick-tutorial.html

+0

आपको बहुत बहुत धन्यवाद, आपका जवाब उत्कृष्ट है! अब मैं जावा में जेनरिक समझने के लिए खुद को और अधिक करीब महसूस करता हूं। इसके अतिरिक्त, मैंने इस तथ्य को याद किया कि, 'व्यक्ति' और 'छात्र' वर्गों के विपरीत, 'व्यक्ति' और 'छात्र' के बीच 'विरासत ' और 'सूची 'के बीच कोई विरासत संबंध नहीं है (जैसा कि मैं समझता हूं, यह वास्तव में नहीं है टाइप एरर के कारण इस सूची में पैरामीटर प्रकारों के बीच संबंध?)। –

+0

हाँ, तो टाइप-एरर का अर्थ है कि 'अंडर-द-हूड' वे सभी रन-टाइम पर सूची हैं। टाइप-सुरक्षा को बनाए रखने के लिए कंपाइलर को सभी सामान्य प्रकार के पैरामीटर से मेल खाना चाहिए और सुनिश्चित करें कि सबकुछ संगत है। इसलिए जेनेरिक टाइप पैरामीटर में विरासत संबंध चीजों की तुलना में थोड़ा अलग तरीके से काम करते हैं जिन्हें पूरी तरह से रन-टाइम प्रकार की जांच द्वारा सत्यापित किया जा सकता है। – sisyphus

+0

मुझे अभी भी समझ में नहीं आ रहा है कि आप क्यों नहीं जोड़ सकते हैं, उदाहरण के लिए, 'सूची' में 'नया कुत्ता() '? पशु> 'बढ़ाता है। क्या संकलक नहीं देख सकता कि कुत्ता वर्ग पशु को बढ़ाता है? – Ogen

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