2012-06-13 18 views
18

यहाँ एक सवाल है, यह पहली कोड सूची ठीक संकलित (JDK 1.6 | JDK 1.7):का मेल कच्चे प्रकार और जेनेरिक तरीके

ArrayList<String> a = new ArrayList<String>(); 
String[] s = a.toArray(new String[0]); 

हालांकि, अगर मैं एक कच्चे प्रकार के रूप में List संदर्भ की घोषणा:

ArrayList a = new ArrayList(); 
String[] s = a.toArray(new String[0]); 

मुझे एक संकलक त्रुटि मिलती है जो String[] आवश्यक है लेकिन Object[] पाया गया था।

इसका मतलब है कि मेरा संकलक Object[] लौटने के रूप में जेनेरिक विधि को String[] प्राप्त करने के बावजूद इसके तर्क के रूप में व्याख्या कर रहा है।

मैं दोगुनी जाँच toArray(myArray) विधि हस्ताक्षर:

<T> T[] toArray(T[] a); 

इसलिए यह एक पैरामिट्रीकृत विधि जिसका प्रकार पैरामीटर <T> सूची के साथ कोई संबंध (अर्थात <E>) है।

मुझे नहीं पता कि कच्चे प्रकार का उपयोग करने से स्वतंत्र प्रकार पैरामीटर का उपयोग करके पैरामीटरयुक्त विधियों के मूल्यांकन को प्रभावित किया जाता है।

  • क्या किसी को पता है कि यह कोड संकलित क्यों नहीं करता है?
  • क्या कोई इस संदर्भ को दस्तावेज करता है जहां कोई व्यवहार दस्तावेज है?
+1

अगर आप '(String []) a.toArray() का उपयोग क्या; चूंकि आप जेनिक्स का उपयोग नहीं कर रहे हैं, इसलिए कास्टिंग एक जरूरी है। –

+0

@HovercraftFullOfEels सुझाव के लिए धन्यवाद। मुझे पता है कि मैं इसे कास्ट कर सकता हूं, लेकिन मैं प्रोग्रामर प्रमाणीकरण के लिए अध्ययन कर रहा हूं और मुझे कुछ जेनेरिक कोड के साथ खेलने के दौरान बस इसके बारे में पता चला और मैं इसे समझा नहीं सकता। इससे पहले कभी ऐसा कुछ नहीं चला था। इसलिए, मैं यह क्यों समझ रहा हूं कि ऐसा क्यों होता है। –

+1

दिलचस्प खोज। विचित्र रूप से पर्याप्त, यदि आप ऑब्जेक्ट (ArrayList ) के रूप में सामान्य पैरामीटर को स्पष्ट रूप से निर्दिष्ट करते हैं तो त्रुटि दूर हो जाती है। ऑब्जेक्ट को छोड़े गए प्रकारों के लिए डिफ़ॉल्ट माना जाता है जो अजीब है। – Perception

उत्तर

22

यह बिल्कुल ठीक नहीं है कि आप क्या उम्मीद करेंगे, लेकिन यदि आप कच्चे रूप में एक सामान्य वर्ग का संदर्भ लेते हैं, तो आप उदाहरण के लिए जेनिक्स किसी भी तरह का उपयोग करने की क्षमता खो देते हैं। यह सामान्य तरीकों को या तो सीमित नहीं है, बाहर की जाँच करें:

public class MyContainer<T> { 

    public List<String> strings() { 
     return Arrays.asList("a", "b"); 
    } 
} 

MyContainer container = new MyContainer<Integer>(); 
List<String> strings = container.strings(); //gives unchecked warning! 

यह JLS के संबंधित भाग (4.8) है:

एक निर्माता (§8.8), उदाहरण के विधि के प्रकार (§8.4, §9.4), या गैर स्थैतिक क्षेत्र (§8।3) एक कच्चे प्रकार सी कि अपनी सुपर-क्लास या superinterfaces से नहीं ली गई है एम कच्चे प्रकार है कि सामान्य घोषणा में अपनी तरह का विलोपन से मेल खाती है सी

करने के लिए इसी
+0

+1 ऐसा प्रतीत होता है कि संकलक कच्चे प्रकार के उपयोग पर एक संकेत लेता है और दिए गए संदर्भ में किसी भी तरह के जेनेरिक को अक्षम करता है। हां दिलचस्प। मुझे आश्चर्य है कि क्या यह जेएलएस में दस्तावेज है। मौका से आपको पता चल जाता है? –

+1

@ एडविन डलोरोजो - मेरा संपादित उत्तर देखें - जेएलएस 4.8 – Premraj

+0

@ एडविन: मैंने इसे अपने उत्तर में उद्धृत किया है, ऐसा लगता है कि प्रेमराज ने भी इसे पाया। –

4

आप एक कच्चे प्रकार के रूप में जेनरिक उपयोग नहीं करने पर संकलक व्यवहार करता है यह और इसलिए हर सामान्य प्रकार Object हो जाता है और इसलिए आप String[] पारित नहीं हो सकता है क्योंकि यह Object[]
की जरूरत है तो यहाँ सौदा है - आप

का उपयोग करते हैं
List l = new ArrayList<String>(); 

आप कच्चे प्रकार का उपयोग कर रहे हैं और इसके सभी उदाहरण सदस्यों ने अपने विलोपन समकक्षों ने ले ली है। विशेष रूप से प्रत्येक एक उदाहरण विधि घोषणा में दिखाई देने वाले पैरामीटरयुक्त प्रकार को अपने कच्चे समकक्ष के साथ बदल दिया गया है। विवरण के लिए जेएलएस 4.8 देखें।

+0

संकलक कैसे कह सकता है कि मैं जेनेरिक का उपयोग नहीं कर रहा हूं, सूची के प्रकार पैरामीटर में जेनेरिक विधि के प्रकार पैरामीटर के साथ कुछ भी नहीं है? –

+0

संकलक जानता है कि आपने 'ए' को ऐरेलिस्ट या ArrayList घोषित किया है या नहीं। यह इस बारे में जानता है ... अच्छा, आपने जो लिखा है उसे देखकर ... ;-) –

+0

जेएलएस संदर्भ के लिए +1। –

0

आपके एरेलेस्टिस्ट गैर-पैरामीटेरेटेड सूची के बाद से कोई प्रकार पैरामीटर पारित नहीं किया जा सकता है, यह केवल जानता है कि यह ऑब्जेक्ट्स रखता है, यही वह है। a.toArray() हमेशा ऑब्जेक्ट [] सरणी लौटाएगा। दोबारा, आपको इसे (String[]) (इसमें सभी खतरों के साथ) डालना होगा यदि आप यह निर्दिष्ट करना चाहते हैं कि इसमें विशिष्ट स्ट्रिंग प्रकार है।

+0

मैं सराहना करता हूं उत्तर, लेकिन मैं 'ArrayList' की आंतरिक सरणी हमेशा जेनरिक्स का उपयोग करने के बावजूद 'ऑब्जेक्ट []' प्रकार का होता हूं। जब मैं पैरामीटरयुक्त 'ArrayList' संदर्भ का उपयोग करता हूं तो यह पैरामीटरयुक्त विधि को प्रभावित नहीं करता है। हालांकि, प्रश्न में विधि को पैरामीटरकृत किया गया है, जो 'टी []' को इसके रिटर्न प्रकार के रूप में उम्मीद करता है। कंपाइलर द्वारा इसे अनदेखा कैसे किया जाता है यदि इसका 'पैरामीटर' के पैरामीटर प्रकार के साथ कुछ लेना देना नहीं है? मैं अभी भी 'टी' और' ई' के बीच संबंध नहीं देख सकता हूं जैसे संकलक इस तरह से व्यवहार करता है। –

5

यह निकटतम वर्णन मैंने पाया है विनिर्देश में इस मनाया व्यवहार का वर्णन करने:

एक निर्माता (§8.8) के प्रकार, उदाहरण के विधि (§8.8, §9.4), या गैर स्थिर क्षेत्र (§8.3) एक कच्चे प्रकार के एम सी से विरासत में नहीं मिला है इसके सुपरक्लास या सुपरइंटरफेस में इसके प्रकार का क्षरण है जो सी से संबंधित सामान्य घोषणा है। एक कच्चे प्रकार सी के एक स्थिर सदस्य की ई सामान्य घोषणा में अपनी तरह सी

करने के लिए इसी रूप में ही है

यह एक गैर स्थिर प्रकार सदस्य को वास्तविक प्रकार पैरामीटर प्रदान करने के एक संकलन समय त्रुटि है एक कच्चे प्रकार का जो सुपरक्लास या superinterfaces से विरासत में नहीं मिला है।

ऊपर के आधार पर, और मनाया व्यवहार, मैं कहना है उसके सुरक्षित कि सभी सामान्य पैरामीटर प्रकार एक कच्चे प्रकार से निकाल दिए जाते है। बेशक, कच्चे प्रकार खुद को के उपयोग गैर विरासत कोड में हतोत्साहित किया जाता है:

कच्चे प्रकार के उपयोग केवल विरासत कोड की अनुकूलता के लिए एक रियायत के रूप में अनुमति दी है। के बाद लिखे गए कोड में कच्चे प्रकारों का उपयोग जावा प्रोग्रामिंग भाषा में सामान्यता का परिचय दृढ़ता से निराश है। यह संभव है कि जावा प्रोग्रामिंग भाषा के भविष्य के संस्करण कच्चे प्रकार के उपयोग को अस्वीकार कर देंगे।

+0

बोल्ड संदर्भ के लिए +1। मैं अनुसंधान धारणा की सराहना करता हूं। यह निश्चित रूप से मेरे लिए चीजों को स्पष्ट बनाता है। –

1

यह दिलचस्प हो सकता है कि इस व्यवहार को "हल" किया जा सकता है। दो इंटरफेस, बेस गैर जेनेरिक इंटरफ़ेस और एक सामान्य इंटरफ़ेस का उपयोग करें। फिर संकलक जानता है कि आधार गैर सामान्य इंटरफ़ेस के सभी कार्य सामान्य नहीं हैं और इन्हें इस तरह से इलाज करेंगे।

स्ट्रीम और फ़ंक्शन चेनिंग का उपयोग करते हुए यह व्यवहार बहुत परेशान है और इसलिए मैं इसे निम्न जैसा हल करता हूं।

public interface GenericInterface<X extends Y> extends BaseInterface 
{ 
    X getValue(); 
} 

public interface BaseInterface 
{ 
    String getStringValue(); 
} 

अब आप चेतावनी या समस्याओं के बिना निम्न कर सकते हैं:

इंटरफ़ेस inheritence के माध्यम से SOUTION

GenericInterface object = ...; 
String stringValue = object.getStringValue();