2012-07-18 13 views
7

ठीक है, तो जावा की अनुमति नहीं है निम्नलिखित:जेनेरिक्स और वाइल्डकार्ड: जावा पसंद करती है "नए फू <Bar<?>>"

Foo<?> hello = new Foo<?>(); 

यह sense-- सब के बाद बना देता है, क्या जेनरिक की बात करता है, तो आप कर रहे हैं है वैसे भी सब कुछ बॉक्स/अनबॉक्स सब कुछ होगा? यह वास्तव में, अधिक पूरा करता है, हालांकि कुछ बिंदु पर, वहाँ एक डाली जो कुछ Bar साथ काम कर रहा है प्राप्त करने के लिए हो सकता है,

Foo<Bar<?>> howdy = new Foo<Bar<?>>(); 

दी:

क्या अजीब है, जावा इस अनुमति नहीं है है। लेकिन अगर जावा कुछ विशिष्टता के साथ ठीक है, कारण है कि यह इस की अनुमति नहीं है ?:

Foo<? extends Mal> bonjour = new Foo<? extends Mal>(); 

एकमात्र कारण मैं पूछता हूँ मैं एक निर्माता के एक वर्ग के पैरामीटर के अंदर "वाइल्डकार्ड पर भरोसा करने की फिक्सिंग कर रहा हूँ है ", और गंभीरता से इसके पीछे के प्रभाव/इरादे को जानना पसंद करेंगे।

संपादित करें: मेरे प्रश्न को स्पष्ट करने के लिए, इन बयानों को किस आधार पर अनुमति/अस्वीकार किया गया है? मुझे पता है कि "जावा कन्स्ट्रक्टर में वाइल्डकार्ड की अनुमति नहीं देता है", लेकिन सवाल यह है कि क्यों यह सब अजीबता है? अगर नेस्टेड वाइल्डकार्ड ठीक हैं तो वाइल्डकार्ड को बाध्य क्यों नहीं किया जाता है?

उत्तर

5

तर्क के लिए: new Foo<?> शायद new Foo<Object> के रूप में बेहतर लिखा जाना चाहिए, इसलिए यहां संकलक प्रतिबंध कोड को लिखने योग्य के रूप में लिखने के लिए मजबूर करता है। आखिरी उदाहरण new Foo<Mak>() भी हो सकता है, क्योंकि Foo<? extends Mal> पर आप कुछ भी नहीं कर सकते हैं कि आप Foo<Mal> पर नहीं कर सकते हैं।ध्यान दें कि बातचीत सत्य नहीं है: Foo<Mal>Mal तर्क स्वीकार कर सकता है जहां Foo<? extends Mal> नहीं है।

दूसरी तरफ, आप वास्तव में Foo ऑब्जेक्ट चाहते हैं जो Bar किसी भी प्रकार की वस्तुओं को संभाल सकता है, इसलिए Foo<Bar<?>> सही समझ में आता है। यह मामला होगा यदि आप केवल Bar के तरीकों तक पहुंचते हैं जो कि प्रकार तर्क पर भरोसा नहीं करते हैं। संकलक के लिए यहां शिकायत करने के लिए कुछ भी नहीं है।

+0

मुझे लगता है कि मैं समझ रहा हूं कि आप क्या कह रहे हैं: यदि कोई कन्स्ट्रक्टर क्लास परम 'मल' स्वीकार करता है, तो उदाहरण मूल रूप से कुछ भी स्वीकार करता है जो 'मल' का उप-वर्ग है (हालांकि उदाहरण के लिए _reference_ को इंगित करने में सक्षम नहीं होगा एक उपclass के साथ जेनेरिक जब तक एक वाइल्डकार्ड निर्दिष्ट नहीं किया गया था।) – Philip

+0

एक साल बाद मेरी टिप्पणी देख रहे हैं ... मुझे पूरा यकीन है कि मैंने कभी भी कहा है कि सबसे अचूक चीजों में से एक है। – Philip

1

जब आप पैरामीटरयुक्त प्रकार के उदाहरण को instanciate, तो आपको एक प्रकार निर्दिष्ट करना होगा। ? और ? extends Mal प्रकार नहीं हैं। Bar<?> एक प्रकार है। आप इस page पर अधिक जानकारी प्राप्त कर सकते हैं।

यहाँ अपने दूसरे मामले के लिए एक उदाहरण है:

Bar<Object> bar1 = ...; 
Bar<String> bar2 = ...; 
List<Bar<?>> list = new ArrayList<Bar<?>>(); 
list.add(bar1); 
list.add(bar2); 

आपको एक सूची में बार उदाहरणों स्टोर करने के लिए कल्पना कर सकते हैं, लेकिन आप अपने प्रकार पैरामीटर पता करने की जरूरत नहीं है।

3

कारण अपने पहले और तीसरे घोषणाओं से काम नहीं करते है JLS §15.9 की वजह से:

यह एक संकलन समय त्रुटि अगर एक वर्ग उदाहरण निर्माण अभिव्यक्ति में इस्तेमाल किया प्रकार तर्क के किसी भी वाइल्डकार्ड प्रकार हैं तर्क (§4.5.1)।

आपकी पहली घोषणा में, ? एक वाइल्डकार्ड प्रकार है। आपकी तीसरी घोषणा में, ? extends Mal एक वाइल्डकार्ड प्रकार है।

कारण आपकी दूसरी घोषणा काम करता है क्योंकि Bar<?> वाइल्डकार्ड प्रकार नहीं है। Bar<?> का प्रकार Bar है।

"कन्स्ट्रक्टर के क्लास पैरामीटर के अंदर वाइल्डकार्ड" का क्या मतलब है?

+0

वैसे हाँ, वे वाइल्डकार्ड हैं और उन मामलों में वाइल्डकार्ड की अनुमति नहीं है - लेकिन मेरा सवाल है, _why_? यह डिजाइन निर्णय क्यों बनाया गया था? तीसरा कोड दूसरे की तुलना में कम वैध क्यों है? – Philip

+0

इसका मतलब है कि 'नया फू > ' – Philip

+0

@Phillip के रूप में मेरा मतलब कुछ और तीसरे कोड ब्लॉक काफी समान हैं। पहले के लिए, 'ऑब्जेक्ट', 'माल', 'सबक्लास ओफमाल', 'सबसबक्लासऑफमाल' के साथ '?' को प्रतिस्थापित किया जा सकता है। तीसरे के लिए, 'ऑब्जेक्ट 'को छोड़कर उपर्युक्त में से किसी के साथ बदल दिया जा सकता है। अभी भी वास्तविक प्रकारों की एक अनंत संख्या है जो '?' से मेल खा सकती है, और संकलक इसे संभाल नहीं सकता है। – Jeffrey

1

new Foo<?> समतुल्य new Foo<SomeRandomTypeIMadeUp> के साथ प्रतिस्थापित किया जा सकता है जहां SomeRandomTypeIMadeUp कोई भी प्रकार है जो उस प्रकार पैरामीटर की सीमा को संतुष्ट करता है। सबसे आसान विकल्प केवल उस प्रकार पैरामीटर के ऊपरी बाउंड को चुनना है, उदा। यदि यह class Foo<T extends X> है, तो new Foo<X> पर्याप्त होगा।

आप पूछ सकते हैं, मैं यह क्यों कह सकता हूं कि मैं किसी भी मनमाना प्रकार पैरामीटर का चयन कर सकता हूं, यहां तक ​​कि कोई भी जो मेरे शेष कार्यक्रम से बिल्कुल कोई कनेक्शन नहीं हो सकता है? क्या वह असुरक्षित नहीं है? जवाब नहीं है, क्योंकि यह ठीक है Foo<?> का मतलब है - प्रकार पैरामीटर कुछ भी हो सकता है, और आप इस पर निर्भर नहीं कर सकते कि यह क्या है। यह आप जो करने के लिए कह रहे हैं उसके बारे में बेहद बेतुकापन दर्शाता है। new Foo<?> के साथ बनाया गया कुछ बहुत ही बेकार होगा, क्योंकि आप इसके साथ कुछ भी नहीं कर सकते हैं जो प्रकार पैरामीटर के प्रकार पर निर्भर करता है।

वाइल्डकार्ड वाले प्रकार आम तौर पर उपयोगी होते हैं। उदाहरण के लिए, आपके पास List<?> प्रकार का तर्क हो सकता है और आप किसी भी प्रकार के List को पास कर सकते हैं, और यह आसानी से सूची से बाहर हो जाता है। लेकिन उस स्थिति में, आप सूची नहीं बना रहे हैं। वह फ़ंक्शन जिसने सूची बनाई और इसे पास कर दिया, शायद आपके पास कुछ गैर-वाइल्डकार्ड प्रकार पैरामीटर था। उस कार्य के दायरे में, आप अभी भी चीजों को सूची में डाल सकते हैं और इसके साथ उपयोगी चीजें कर सकते हैं। यदि कोई फ़ंक्शन List<?> बनाना था; यह बहुत बेकार होगा - आप null को छोड़कर कोई तत्व नहीं डाल सकते हैं।

यही कारण है कि आपको new Foo<?> करने की अनुमति नहीं है: यह पूरी तरह बेकार है; यदि आप इसका उपयोग करना चाहते हैं तो आप शायद जेनेरिक गलत का उपयोग कर रहे हैं। और बेहद दुर्लभ मामले में आप वास्तव में इसे चाहते हैं, एक तैयार विकल्प है, new Foo<AnyTypeThatSatisfiesTheBounds>

Foo<Bar<?>> बहुत अलग है। Bar<?> एक विशिष्ट प्रकार है। Foo<Bar<?>> का मतलब यह नहीं है कि आप इसे Foo<Bar<Something>> असाइन कर सकते हैं; बल्कि, यह अवैध है; Foo के प्रकार पैरामीटर से मेल खाना चाहिए यदि वे वाइल्डकार्ड नहीं हैं। List<Bar<?>> के साथ वाइल्डकार्ड के विपरीत, आप इसमें ऑब्जेक्ट डाल सकते हैं और ऑब्जेक्ट्स निकाल सकते हैं।