2011-12-13 11 views
20

की एक सरणी बनाना वास्तव में, सवालसामान्य संग्रह

Creating an array of generic anything. 

क्यों संकलक यह की देखभाल नहीं कर सकते होना चाहिए?

निम्नलिखित को एक त्रुटि के रूप में चिह्नित किया जाएगा - जेनेरिक सरणी नहीं बना सकता है।

List<MyDTO>[] dtoLists = {new ArrayList<MyDTO>(), anExistingDtoList}; 

कि काबू पाने के लिए, मैं

List<MyDTO>[] dtoLists = (List<MyDTO>[])Array.newInstance(ArrayList.class, 2); 
dtoLists[0] = new ArrayList<MyDTO>(); 
dtoLists[1] = anExistingDtoList; 

तो की जरूरत है, क्यों संकलक दूसरे मामले में पहला मामला नहीं बदल सकते?

मुझे एहसास है कि जेनेरिक संकलन-समय निर्धारित करते हैं और रन-टाइम निर्धारित नहीं करते हैं, जबकि सरणी रन-टाइम निर्धारित होती हैं और इसलिए सरणी बनाने के लिए एक निर्धारित प्रकार की आवश्यकता होती है।

तकनीकी/तार्किक बाधाएं कंपाइलर डिज़ाइनर क्या मुठभेड़ करेंगे जो उन्हें लागू करने में सक्षम होने से रोकेंगी?

क्या भाषा पूरी तरह दार्शनिक है, भाषा ऑर्थोगोनैलिटी के विषय में? यदि हां, तो ऐसा व्यवहार भाषा ऑर्थोगोनलिटी का उल्लंघन कैसे करेगा?

क्या यह जटिलता का सवाल है? जटिलता समझाओ।

मुझे उम्मीद है कि मेरे प्रश्न के उत्तर मुझे जावा संकलक व्यवहार में बेहतर अंतर्दृष्टि प्रदान करेंगे जब यह जेनेरिक से संबंधित है।

साइड नोट: चलो खुश होने से रोकें। उत्तर Array of Generic List मेरे प्रश्न का उत्तर नहीं देते हैं। संकलक स्वचालित रूप से रूपांतरण क्यों नहीं कर सकते हैं?

+0

[जेनेरिक सूची के ऐरे] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/7810074/array-of-generic-list) – Thilo

+1

उस डुप्लिकेट पर शीर्ष उत्तर देखें। इसमें एक उदाहरण है कि इसकी अनुमति क्यों नहीं है। – Thilo

+2

यह एक डुप्लिकेट नहीं है। मेरा प्रश्न संकलक डिजाइन मुद्दों से संबंधित उत्तरों के लिए पूछता है। –

उत्तर

8

वास्तव में जावा varargs के लिए सामान्य सरणी पैदा करता है, तो आप

List<MyDTO>[] dtoLists = array(new ArrayList<MyDTO>(), anExistingDtoList); 

@SafeVarargs 
static <E> E[] array(E... array) 
{ 
    return array; 
} 

कर सकते हैं क्यों स्पष्ट सामान्य सरणी मना रचना है के रूप में, यह प्रकार विलोपन के साथ कुछ है। (उपरोक्त समाधान में एक ही चिंता मौजूद है, लेकिन @SafeVarargs द्वारा दबाया गया) हालांकि यह बहस योग्य है; चिंता को संभालने के विभिन्न तरीके हैं, एक संकलक चेतावनी शायद पर्याप्त है। लेकिन वे एकमुश्त यह प्रतिबंध लगाने के लिए चुना है, शायद इसलिए कि सरणियों वैसे भी अब है कि हम सामान्य संग्रह

है नहीं रह गया है महत्वपूर्ण हैं
+0

जावा के सरणी के समान है, सी ++ प्रोग्रामर होने के नाते मेरे लिए बहुत उपयोगी है। जावा में, मैं पॉइंटर्स पास नहीं कर सकता। मुझे पॉइंटर की तरह इसे पास करने के लिए किसी ऑब्जेक्ट में या सरणी में एक चर होना चाहिए। –

+0

मेरा मतलब है, जेनेरिक से पहले, हम 'सूची ' नहीं कर सका, इसलिए स्थिर टाइपिंग के लिए 'Foo [] 'होना महत्वपूर्ण है। वह महत्व चला गया है। निश्चित रूप से बुनियादी बिल्डिंग ब्लॉक के रूप में सरणी अभी भी महत्वपूर्ण हैं। – irreputable

3

मुझे पता है कि, इस मुद्दे के कामकाज के सापेक्ष, Array.newInstance() कॉल करने का एक महंगा तरीका है। आईआईआरसी इसमें शामिल अन्य प्रतिबिंब के बीच, सरणी को तुरंत चालू करने के लिए मूल विधि का उपयोग करता है। मैं किसी भी आंकड़े की पेशकश नहीं कर सकता, लेकिन यह सामान्य कार्यक्षमता की अनुमति देने के लिए संकलक द्वारा स्वचालित रूप से प्रतिस्थापित नहीं होने के लिए ऐसी कार्यक्षमता के लिए पर्याप्त कारण है। विशेष रूप से ArrayList, आदि का अस्तित्व दिया गया है, यह सिर्फ एक दबाने वाली समस्या की तरह प्रतीत नहीं होता है।

1

संकलनकर्ता अनायास रूपांतरण प्रदर्शन कर सकते हैं, वे तो बस के लिए नहीं निर्दिष्ट क्योंकि सामान्य सरणियों व्यवहार नहीं कर सकते हैं गैर-जेनेरिक सरणी की तरह।

एक सरणी जिसका प्रकार A[], जहां A एक संदर्भ प्रकार, सरणी के एक घटक के लिए एक काम है कि मूल्य निर्धारित किये जाने से आबंटित है रन टाइम पर चेक किया गया है सुनिश्चित करने के लिए है के लिए:

10.5. Array Store Exception देखें घटक के लिए।

यदि आवंटित मूल्य का प्रकार असाइनमेंट नहीं है-घटक प्रकार के साथ संगत, ArrayStoreException फेंक दिया गया है।

यदि किसी सरणी का घटक प्रकार पुनः प्राप्त करने योग्य नहीं था, तो जावा वर्चुअल मशीन पिछले अनुच्छेद में वर्णित स्टोर चेक नहीं कर सका। यही कारण है कि गैर-पुन: प्रयोज्य तत्व प्रकार के साथ एक सरणी निर्माण अभिव्यक्ति प्रतिबंधित है।

एक List<MyDTO>[] अगर हम इसे में List के कुछ अन्य प्रकार डाल फेंक नहीं होगा, तो यह एक सरणी के रूप में व्यवहार नहीं करता है। उद्धरण से अंतिम वाक्य पर ध्यान दें: "यही कारण है कि एक गैर-पुन: प्रयोज्य तत्व प्रकार के साथ एक सरणी निर्माण अभिव्यक्ति प्रतिबंधित है।" यही कारण है, ऐसा होना निर्दिष्ट है। (और, रिकॉर्ड, this reasoning has always existed के लिए, तो यह मौजूद था जब सवाल 2011 में पोस्ट किया गया था)

हम अभी भी यह कर सकते हैं:

@SuppressWarnings({"unchecked","rawtypes"}) 
List<MyDTO>[] dtoLists = new List[] { 
    new ArrayList<MyDTO>(), anExistingDtoList 
}; 

या इस:

@SuppressWarnings("unchecked") 
List<MyDTO>[] dtoLists = (List<MyDTO>[]) new List<?>[] { 
    new ArrayList<MyDTO>(), anExistingDtoList 
}; 

(स्थिर रूप से तर्क प्रकारों की जांच करने के अलावा, varargs चीज समतुल्य है: creates a List[] और suppresses warnings।)

अब, निश्चित रूप से, विनिर्देशन बदला जा सकता है जैसे कुछ "अगर मूल्य का प्रकार असाइनमेंट नहीं है- के साथ संगत कच्चे प्रकार का घटक प्रकार ...", लेकिन बिंदु क्या है? यह कुछ असामान्य परिस्थितियों में कुछ हद तक पात्रों को बचाएगा लेकिन अन्यथा उन लोगों के लिए चेतावनियों को दबाएगा जो प्रभाव को नहीं समझते हैं।

इसके अलावा, the tutorial और अन्य सामान्य स्पष्टीकरण जो मैंने देखा है, यह प्रदर्शित नहीं करता है कि टाइप सिस्टम कोविरिएंट सरणी में कैसे बेक किया गया है।

// (declaring our own because Arrays.fill is defined as 
// void fill(Object[], Object) 
// so the next examples would more obviously pass) 
static <T> void fill(T[] arr, T elem) { 
    Arrays.fill(arr, elem); 
} 

आप जानते हैं कि इस संकलित:

उदाहरण के लिए, निम्नलिखित घोषणा दिए गए?

// throws ArrayStoreException 
fill(new String[1], new Integer(0)); 

और यह भी संकलित:

static <T, U extends T> void fill(T[] arr, U elem) {...} 

लेकिन वह केवल एक था:

// doesn't throw ArrayStoreException 
fill(dtoLists, new ArrayList<Float>()); 

जावा 8 से पहले, हम उन कॉल करने के लिए fill यह निम्नलिखित घोषणा देकर असफल बना सकता है प्रकार अनुमान के साथ समस्या, और अब यह List<MyDTO>[] में अंधेरे से List<Float> डालने "सही ढंग से" काम करता है।

इसे ढेर प्रदूषण कहा जाता है। यह कुछ समय बाद फेंकने के लिए ClassCastException का कारण बन सकता है, संभवतः कहीं भी समस्या के कारण पूरी तरह से असंबंधित होने की संभावना है। List जैसे जेनेरिक कंटेनर के साथ हीप प्रदूषण raw types का उपयोग करने जैसी अधिक स्पष्ट असुरक्षित कार्रवाइयों की आवश्यकता है, लेकिन यहां, हम ढेर प्रदूषण को स्पष्ट रूप से और बिना किसी चेतावनी के कारण बना सकते हैं।

जेनेरिक सरणी (और वास्तव में, सामान्य रूप से सरणी) केवल हमें परिस्थितियों में सबसे सरल जांच देते हैं।

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

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