2016-03-17 14 views
6

को देखते हुए AGenericClass नीचे के रूप में की घोषणा की:ये तीन पैरामीटरयुक्त चर अलग-अलग कैसे होते हैं?

public class AGenericClass<T> { 
    T subject; 
    public void setSubject(T subject) { 
    this.subject = subject; 
    } 
} 

क्या चर एक, , और के बीच मतभेद रहे हैं?

AGenericClass<String> a = new AGenericClass<>(); 
AGenericClass<?> b = new AGenericClass<String>(); 
AGenericClass c = new AGenericClass<String>(); 

a.setSubject("L"); // OK. 

b.setSubject("M"); // Error: setSubject(capture<?>) cannot be 
        // applied to (java.lang.String) 

c.setSubject("N"); // Warning: Unchecked call to 'setSubject(T)' 
        // as a member of raw type 'AGenericClass' 

एक और सभी आईडीई से बिना किसी शिकायत के घोषणा की जाती है, लेकिन जब setSubject कहा जाता है वे सब अलग ढंग से व्यवहार।

उत्तर

3

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


AGenericClass<String> प्रकार String की विशेष रूप से एक सामान्य वर्ग का एक उदाहरण की घोषणा की। इस सामान्य के साथ किए गए किसी भी ऑपरेशन के लिए एक सामान्य पैरामीटर की आवश्यकता होती है, उस पैरामीटर को String तक बाध्य किया जाएगा, और संकलन समय पर प्रकार की जांच और टाइप को लागू करेगा।

यह कहना है कि यदि आपके पास AGenericClass<String> a = new AGenericClass<>(); है और आप a.setSubject(3) पर कॉल करने का प्रयास करते हैं, तो जावा अनुप्रयोगों को संकलित करने की अनुमति नहीं देगा क्योंकि प्रकार मेल नहीं खाते हैं।

AGenericClass<?>अज्ञात प्रकारों के साथ एक सामान्य वर्ग का उदाहरण घोषित करता है।औपचारिक रूप से, ? एक वाइल्डकार्ड जिसमें यह किसी भी प्रकार है, जो ठीक है अगर आप इसे से तत्वों प्राप्त करना चाहते हैं, लेकिन नहीं ठीक हो सकता है आप इसे से तत्वों जोड़ना चाहते हैं है।

कारण? AGenericClass<?> वास्तव में AGenericClass<? extends Object> है, और यह in and out principle की वजह से महत्वपूर्ण है। आम तौर पर (हालांकि यह सख्त गारंटी नहीं है), extends के साथ जेनेरिक कुछ भी केवल पढ़ने-योग्य ऑपरेशन का तात्पर्य है।

जैसा कि मैंने पहले भी कहा है, यह, से पढ़ने के लिए ठीक है, क्योंकि आप एक वर्ग है जो सबसे एक Object पर गारंटी रहे हैं, लेकिन जब से तुम नहीं जानते कि तुम यह करने के लिए नहीं लिख सकते हैं, और न ही आप गारंटी ले सकते हैं , किसी भी कॉल से आप किस प्रकार की वस्तु को जोड़ रहे हैं।

AGenericClassबिना प्रकार की घोषणा एक कच्ची प्रकार है। You can read more about them here, लेकिन पता है कि वे विरासत संगतता कारणों के लिए मौजूद हैं। यदि आपका कोड कच्चे प्रकार का उपयोग करता है, तो आप संकलन समय को खो देते हैं और आपका कोड रनटाइम के दौरान ClassCastException फेंकने में हवा हो सकता है, जो डीबग, निदान और हल करने के लिए कहीं अधिक कठिन है।

1
AGenericClass<String> a = new AGenericClass<>(); 

इंगित करता है इस String प्रकार का एक AGenericClass है और प्रकार पैरामीटर टी के स्थान पर पैरामीटर में स्ट्रिंग को स्वीकार करेंगे जब आप a.setSubject("L"); कहा जाता है तो यह शिकायत नहीं है।

AGenericClass<?> b = new AGenericClass<String>(); 

? इंगित करता है यह है unbounded वाइल्डकार्ड, एक

प्रकार निर्दिष्ट या अज्ञात नहीं है

इस के साथ

का मतलब है, कि सभी की गारंटी देता है है वापसी है प्रकार, Object होगा यदि आप public T getSubject() जैसी विधि है। आप ऑब्जेक्ट प्रकार के चर को असाइन कर सकते हैं या इसे पैरामीटर के रूप में पास कर सकते हैं जहां ऑब्जेक्ट की अपेक्षा की जाती है। सेट ऑपरेशन करने में सक्षम नहीं होंगे। extends और super दो कीवर्ड हैं जिनका उपयोग आप निम्न/ऊपरी बाउंड को सेट करने के लिए ? के साथ कर सकते हैं जिसे आप आगे खोजना चाहते हैं।

AGenericClass c = new AGenericClass<String>(); 

Warning: Unchecked call to 'setSubject(T)'.. का संकेत है कि यह कॉल कच्चे प्रकार के रूप में किया जा रहा है, तो यह शिकायत नहीं होगी, भले ही आप setSubject(new Integer(1)) अर्थात कहते हैं, यह प्रकार की सुरक्षा के लिए किसी भी जांच नहीं करता है। लेकिन बाद में जब आप इस विषय को प्राप्त करने और स्ट्रिंग पर डालने का प्रयास करते हैं तो आपको ClassCastException का सामना करना पड़ेगा क्योंकि आपने संकलक चेतावनी को अनदेखा कर दिया है और हमें जेनेरिक द्वारा प्रदान किए गए प्रकार के सुरक्षा लाभ नहीं मिलते हैं।

2
AGenericClass<String> a = new AGenericClass<>(); 

तो "Diamond" सामान्य instantiating कहा जाता है। जब आप जेनेरिक प्रकार के कन्स्ट्रक्टर पर खाली <> सेट करते हैं, तो कंपाइलर संदर्भ से प्रकार निर्धारित करने का प्रयास करेगा। उदाहरण में केस कंपाइलर <String> का उपयोग करेगा क्योंकि a<String> के साथ घोषित किया गया है।


AGenericClass<?> b = new AGenericClass<String>(); 

यह नाम "Unbounded Wildcards"। bअज्ञात प्रकार के जेनेरिक के रूप में बनाया जाएगा। जब आप setSubject() का उपयोग करने का प्रयास कर रहे हैं, तो संकलक तर्क के प्रकार की जांच नहीं कर सकता है। यह आपको अपवाद क्यों मिलता है। इस समस्या को हल करने के लिए, आप परिभाषित जेनेरिक प्रकार के साथ सहायक विधि बना सकते हैं।


AGenericClass c = new AGenericClass<String>(); 

इस मामले c "Raw type" के रूप में घोषित किया। c<Object> पैरामीटर के साथ जेनेरिक के रूप में बनाया जाएगा। क्योंकि आप String को Object पर असाइन कर सकते हैं, विधि setSubject()String के साथ काम करेगी। असल में, यह किसी भी प्रकार के साथ काम करेगा, जो Object से विरासत में मिला है, और संभावित रूप से यह त्रुटि का कारण हो सकता है। और संकलक आपको इसके बारे में चेतावनी देता है।

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