क्या कारण है कि मैं जावा में जेनेरिक सरणी प्रकार नहीं बना सकता हूँ?


273

क्या कारण है कि जावा हमें करने की अनुमति नहीं देता है

private T[] elements = new T[initialCapacity];

मैं समझ सकता था कि .NET ने हमें ऐसा करने की अनुमति नहीं दी है, जैसा कि .NET में आपके पास मूल्य प्रकार हैं जो कि रन-टाइम में अलग-अलग आकार हो सकते हैं, लेकिन जावा में सभी प्रकार के टी ऑब्जेक्ट संदर्भ होंगे, इस प्रकार एक ही आकार होगा ( यदि मैं गलत हूं तो मुझे सही करों)।

क्या कारण है?


29
तुम्हारी किस बारे में बोलने की इच्छा थी? आप ऐसा .NET में बिल्कुल कर सकते हैं। - मैं यहां यह जानने की कोशिश कर रहा हूं कि मैं जावा में ऐसा क्यों नहीं कर सकता।
BrainSlugs83

@ BrainSlugs83 - कृपया कुछ कोड उदाहरण या ट्यूटोरियल के लिए एक लिंक जोड़ें जो दिखाता है कि।
मास्टरजो

यह भी देखें - stackoverflow.com/questions/21577493/…
MasterJoe2

1
@ MasterJoe2 ओपी के प्रश्न में उपरोक्त कोड है जिसका मैं उल्लेख कर रहा हूं। यह C # में ठीक काम करता है, लेकिन जावा में नहीं। - प्रश्न में कहा गया है कि यह न तो काम करता है, जो गलत है। - सुनिश्चित नहीं है कि आगे इस पर चर्चा करने में कोई मूल्य है।
ब्रेनस्ल्गस83

जवाबों:


204

ऐसा इसलिए है क्योंकि जावा के सरणियों (जेनरिक के विपरीत) में रनटाइम के दौरान, इसके घटक प्रकार के बारे में जानकारी होती है। जब आप सरणी बनाते हैं तो आपको घटक प्रकार पता होना चाहिए। चूंकि आप नहीं जानते कि Tरनटाइम पर क्या है, आप ऐरे को नहीं बना सकते।


29
लेकिन मिटाने का क्या? वह लागू क्यों नहीं होता?
Qix - मोनासा ने

14
ArrayList <SomeType>फिर कैसे करता है?
थम्बज

10
@ थम्बज: आपका मतलब है new ArrayList<SomeType>()? सामान्य प्रकार में रनटाइम पर टाइप पैरामीटर नहीं होता है। प्रकार पैरामीटर का उपयोग निर्माण में नहीं किया जाता है। new ArrayList<SomeType>()या new ArrayList<String>()उसके द्वारा उत्पन्न कोड में कोई अंतर नहीं है new ArrayList()
newacct

8
मैं ArrayList<T>इसके बारे में अधिक पूछ रहा था कि इसके साथ कैसे काम होता है ' private T[] myArray। कहीं कोड में, यह सामान्य प्रकार टी का एक सरणी होना चाहिए, तो कैसे?
थम्बज

21
@Thumbz: इसमें रनटाइम प्रकार की कोई सरणी नहीं है T[]। इसमें रनटाइम प्रकार की एक सरणी होती है Object[], और या तो 1) स्रोत कोड में एक चर होता है Object[](यह है कि यह नवीनतम Oracle जावा संस्करण में है); या 2) स्रोत कोड में एक प्रकार का एक चर होता है T[], जो एक झूठ है, लेकिन Tकक्षा के दायरे के अंदर मिटाए जाने के कारण समस्याएं पैदा नहीं करता है ।
Newacct

137

उद्धरण:

सामान्य प्रकार के ऐरे की अनुमति नहीं है क्योंकि वे ध्वनि नहीं हैं। समस्या जावा सरणियों की बातचीत के कारण है, जो सांख्यिकीय रूप से ध्वनि नहीं हैं, लेकिन गतिशील रूप से जाँच की जाती हैं, जेनेरिक के साथ, जो सांख्यिकीय रूप से ध्वनि हैं और गतिशील रूप से जाँच नहीं की जाती हैं। यहां बताया गया है कि आप कैसे खामियों का फायदा उठा सकते हैं:

class Box<T> {
    final T x;
    Box(T x) {
        this.x = x;
    }
}

class Loophole {
    public static void main(String[] args) {
        Box<String>[] bsa = new Box<String>[3];
        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3); // error not caught by array store check
        String s = bsa[0].x; // BOOM!
    }
}

हमने इस समस्या को सांविधिक रूप से सुरक्षित सरणियों (उर्फ वेरियन) का उपयोग करके हल करने का प्रस्ताव दिया था, लेकिन टाइगर के लिए इसे अस्वीकार कर दिया गया था।

- बाद में

(मेरा मानना ​​है कि यह नील गेयर है , लेकिन मुझे यकीन नहीं है)

इसे यहाँ संदर्भ में देखें: http://forums.sun.com/thread.jspa?threadID=457033&forumID=316


3
ध्यान दें कि मैंने इसे एक CW बना दिया क्योंकि जवाब मेरा नहीं है।
बार्ट कियर्स

10
यह बताता है कि यह क्यों असुरक्षित नहीं हो सकता है। लेकिन प्रकार के सुरक्षा मुद्दों को संकलक द्वारा चेतावनी दी जा सकती है। तथ्य यह है कि ऐसा करना संभव भी नहीं है, लगभग उसी कारण से कि आप ऐसा क्यों नहीं कर सकते हैं new T()। जावा में प्रत्येक सरणी, डिजाइन द्वारा, T.classइसके अंदर घटक प्रकार (यानी ) को संग्रहीत करता है; इसलिए आपको इस तरह की एक सरणी बनाने के लिए रनटाइम पर टी की कक्षा की आवश्यकता है।
newacct

2
आप अभी भी उपयोग कर सकते हैं new Box<?>[n], जो कभी-कभी पर्याप्त हो सकता है, हालांकि यह आपके उदाहरण में मदद नहीं करेगा।
बार्टोज़ क्लीमेक

1
@BartKiers मुझे यह नहीं मिला ... यह अभी भी संकलित नहीं है (जावा -8): Box<String>[] bsa = new Box<String>[3];क्या मैंने जावा -8 में कुछ भी बदलाव किया है और क्या मुझे लगता है?
यूजीन

1
@ यूजीन, विशिष्ट जेनेरिक प्रकार के एरे को अनुमति नहीं दी जाती है क्योंकि वे नमूने में प्रदर्शित प्रकार की सुरक्षा को नुकसान पहुंचा सकते हैं। यह जावा के किसी भी संस्करण में अनुमति नहीं है। जवाब शुरू होता है "सामान्य प्रकार के एरर्स की अनुमति नहीं है क्योंकि वे ध्वनि नहीं हैं।"
गार्नेट

47

एक सभ्य समाधान प्रदान करने में विफल होने से, आप बस कुछ खराब आईएमएचओ के साथ समाप्त होते हैं।

आस-पास का सामान्य कार्य इस प्रकार है।

T[] ts = new T[n];

के साथ प्रतिस्थापित किया जाता है (मानकर टी वस्तु का विस्तार करती है और दूसरी श्रेणी की नहीं)

T[] ts = (T[]) new Object[n];

मैं पहले उदाहरण को पसंद करता हूं, हालांकि दूसरे को पसंद करने के लिए अधिक अकादमिक प्रकार प्रतीत होते हैं, या सिर्फ इसके बारे में नहीं सोचना पसंद करते हैं।

आप केवल एक वस्तु का उपयोग क्यों नहीं कर सकते हैं इसके अधिकांश उदाहरण [] समान रूप से सूची या संग्रह (जो समर्थित हैं) पर लागू होते हैं, इसलिए मैं उन्हें बहुत खराब तर्क के रूप में देखता हूं।

नोट: यह उन कारणों में से एक है, जो संग्रह पुस्तकालय स्वयं चेतावनियों के बिना संकलित नहीं करता है। यदि आप इस उपयोग-मामले को चेतावनी के बिना समर्थित नहीं किया जा सकता है, तो कुछ को जेनेरिक मॉडल IMHO के साथ मूलभूत रूप से तोड़ दिया गया है।


6
आपको दूसरे के साथ सावधान रहना होगा। यदि आप किसी ऐसे व्यक्ति से अपेक्षा करते हैं, जो अपेक्षा करता है, String[]तो (या यदि आप इसे किसी ऐसे क्षेत्र में संग्रहित करते हैं, जो सार्वजनिक रूप से सुलभ है T[], और कोई इसे पुनर्प्राप्त करता है), तो उन्हें एक ClassCastException मिलेगी।
newacct

4
मैंने इस जवाब को वोट दिया क्योंकि आपके पसंदीदा उदाहरण को जावा में अनुमति नहीं है और आपका दूसरा उदाहरण क्लासकैस्ट अपवाद हो सकता है
जोस रॉबर्टो आराजो जूनियर

5
@ JoséRobertoAraújoJúnior यह स्पष्ट है कि पहले उदाहरण को दूसरे उदाहरण से बदलने की आवश्यकता है। आपके लिए यह बताना अधिक उपयोगी होगा कि दूसरा उदाहरण क्लासकैस्ट अपवाद को क्यों फेंक सकता है क्योंकि यह सभी के लिए स्पष्ट नहीं होगा।
पीटर लॉरी

3
@PeterLawrey मैंने एक स्व-उत्तर वाला प्रश्न बनाया है, जिसमें दिखाया गया है कि T[] ts = (T[]) new Object[n];एक बुरा विचार क्यों है: stackoverflow.com/questions/21577493/…
जोस रॉबर्टो अराउजो जूनियर

1
@MarkoTopolnik मुझे आपकी सभी टिप्पणियों का जवाब देने के लिए एक पदक दिया जाना चाहिए ताकि मैंने जो पहले ही कहा है, उसी बात को समझाने के लिए, केवल एक चीज जो मेरे मूल कारण से बदल गई है, वह यह है कि मैंने कहा कि वह T[] ts = new T[n];एक वैध उदाहरण था। मैं वोट रखूंगा क्योंकि वह जवाब दे सकता है और अन्य देवों के लिए मुद्दों और भ्रमों का कारण बन सकता है। इसके अलावा, मैं इस बारे में टिप्पणी करना बंद कर दूंगा।
जोस रॉबर्टो आराजो जूनियर

38

एरेव्स कोविरेंट हैं

Arrays को सहसंयोजक कहा जाता है जिसका मूल रूप से मतलब है कि, जावा के उप- नियमों को देखते हुए, एक प्रकार के सरणी T[]में प्रकार Tया किसी भी उप- प्रकार के तत्व शामिल हो सकते हैं T। उदाहरण के लिए

Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);

लेकिन इतना ही नहीं, जावा के S[]उप- नियम भी यह कहते हैं कि एक सरणी का एक उपप्रकार है T[]यदि Sइसका उप-प्रकार है T, इसलिए, ऐसा कुछ भी मान्य है:

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;

क्योंकि जावा में Integer[]उप- नियम के अनुसार, एक सरणी एक सरणी का उप-प्रकार हैNumber[] क्योंकि पूर्णांक संख्या का एक उपप्रकार है।

लेकिन यह उप-नियम नियम एक दिलचस्प सवाल पैदा कर सकता है: अगर हम ऐसा करने की कोशिश करते हैं तो क्या होगा?

myNumber[0] = 3.14; //attempt of heap pollution

यह अंतिम पंक्ति बस ठीक संकलित करेगी, लेकिन यदि हम इस कोड को चलाते हैं, तो हमें ए ArrayStoreException क्योंकि हम एक पूर्णांक सरणी में एक डबल डालने की कोशिश कर रहे हैं। तथ्य यह है कि हम एक संख्या संदर्भ के माध्यम से सरणी तक पहुंच रहे हैं यहां अप्रासंगिक है, क्या मायने रखता है कि सरणी पूर्णांक का एक सरणी है।

इसका मतलब है कि हम संकलक को मूर्ख बना सकते हैं, लेकिन हम रन-टाइम प्रकार प्रणाली को मूर्ख नहीं बना सकते। और ऐसा इसलिए है क्योंकि सरणियाँ वे हैं जिन्हें हम एक रिफ़ेक्टिव प्रकार कहते हैं। इसका मतलब यह है कि रन-टाइम पर जावा को पता है कि यह सरणी वास्तव में पूर्णांक के एक सरणी के रूप में तात्कालिक थी, जो केवल प्रकार के संदर्भ के माध्यम से एक्सेस करने के लिए होती है।Number[]

इसलिए, जैसा कि हम देख सकते हैं, एक चीज वस्तु का वास्तविक प्रकार है, एक अन्य चीज उस संदर्भ का प्रकार है जिसे हम इसे एक्सेस करने के लिए उपयोग करते हैं, है ना?

जावा पीढ़ी के साथ समस्या

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

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

आइए अब निम्नलिखित असुरक्षित कोड पर विचार करें:

List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution

यदि जावा कंपाइलर हमें ऐसा करने से नहीं रोकता है, तो रन-टाइम टाइप सिस्टम हमें रोक भी नहीं सकता है, क्योंकि रन टाइम में कोई रास्ता नहीं है, यह निर्धारित करने के लिए कि यह सूची केवल पूर्णांकों की सूची होनी चाहिए थी। जावा रन-टाइम हमें इस सूची में जो कुछ भी चाहिए, वह तब डाल देगा, जब इसमें केवल पूर्णांक होना चाहिए, क्योंकि जब इसे बनाया गया था, तो इसे पूर्णांक की सूची के रूप में घोषित किया गया था। यही कारण है कि संकलक लाइन नंबर 4 को अस्वीकार कर देता है क्योंकि यह असुरक्षित है और यदि अनुमति दी गई है तो यह टाइप सिस्टम की मान्यताओं को तोड़ सकता है।

जैसे, जावा के डिजाइनरों ने सुनिश्चित किया कि हम कंपाइलर को बेवकूफ नहीं बना सकते। यदि हम संकलक को बेवकूफ नहीं बना सकते हैं (जैसा कि हम सरणियों के साथ कर सकते हैं) तो हम रन-टाइम प्रकार प्रणाली को भी नहीं बेवकूफ बना सकते हैं।

जैसे, हम कहते हैं कि जेनेरिक प्रकार गैर-पुन: प्रयोज्य हैं, क्योंकि रन टाइम पर हम जेनेरिक प्रकार की सही प्रकृति का निर्धारण नहीं कर सकते हैं।

मैंने इस उत्तर के कुछ हिस्सों को छोड़ दिया है जिसे आप यहाँ पूरा लेख पढ़ सकते हैं: https://dzone.com/articles/covariance-and-wravravce


32

यह असंभव है कि जावा कंपाइलर स्तर पर अपनी जेनरिक को पूरी तरह से लागू करता है, और प्रत्येक वर्ग के लिए केवल एक ही क्लास फाइल है। इसे टाइप एरासुरे कहते हैं

रनटाइम के समय, संकलित वर्ग को अपने सभी उपयोगों को एक ही बाईटेकोड के साथ संभालने की आवश्यकता होती है। तो, new T[capacity]बिल्कुल पता नहीं होगा कि किस प्रकार की तात्कालिकता की आवश्यकता है।


17

जवाब पहले ही दे दिया गया था लेकिन अगर आपके पास पहले से ही T का इंस्टेंस है तो आप ऐसा कर सकते हैं:

T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);

आशा है, मैं मदद कर सकता हूँ, Ferdi265


1
यह एक अच्छा उपाय है। लेकिन यह अनियंत्रित चेतावनी (ऑब्जेक्ट से टी [] तक डाली जाएगी)। एक और "धीमा" लेकिन "चेतावनी-मुक्त" समाधान होगा T[] ts = t.clone(); for (int i=0; i<ts.length; i++) ts[i] = null;:।
मध्याह्न

1
इसके अलावा, अगर हमने जो रखा है T[] t, वह यह होगा (T[]) Array.newInstance(t.getClass().getComponentType(), length);। मैंने यह पता लगाने के लिए कुछ समय बिताया getComponentType()। आशा है कि यह दूसरों की मदद करता है।
मध्याह्न

1
@ मैडनाइट t.clone()वापस नहीं आएगा T[]। क्योंकि tइस उत्तर में एरियर नहीं है।
एक्समेन

6

मुख्य कारण इस तथ्य के कारण है कि जावा में सरणियाँ सहवर्ती हैं।

यहाँ एक अच्छा अवलोकन है


मैं यह नहीं देखता कि आप कैसे "नया T [5]" का समर्थन कर सकते हैं, यहां तक ​​कि अपरिवर्तनीय सरणियों के साथ भी।
दिमित्रिस आंद्रेउ

2
@DimitrisAndreou खैर, यह पूरी तरह से जावा डिजाइन में त्रुटियों की एक कॉमेडी है। यह सब सरणी कोवरियन के साथ शुरू हुआ। फिर, जब आप सरणी सहप्रसरण है, तो आप डाल सकता String[]करने के लिए Objectऔर एक स्टोर Integerमें। तो फिर उन्हें सरणी स्टोर ( ArrayStoreException) के लिए रनटाइम प्रकार की जांच को जोड़ना पड़ा, क्योंकि समस्या को संकलन-समय पर पकड़ा नहीं जा सकता था। (अन्यथा, Integerवास्तव में एक अटक सकता है String[]और जब आप इसे पुनः प्राप्त करने की कोशिश करेंगे तो आपको एक त्रुटि मिलेगी, जो भयानक होगी।) ...
रेडन रोसबोरो

2
@DimitrisAndreou ... फिर, एक बार जब आप एक दूर ध्वनि संकलन समय जांच के स्थान पर रनटाइम चेक लगाते हैं, तो आप टाइप इरेज़र (एक दुर्भाग्यपूर्ण डिज़ाइन दोष - केवल पिछड़े संगतता के लिए शामिल) में चलाते हैं। टाइप इरेज़र का मतलब है कि आप जेनेरिक प्रकारों के लिए रनटाइम टाइप चेक नहीं कर सकते । इसलिए, सरणी भंडारण प्रकार की समस्या से बचने के लिए, आप बस सामान्य सरणियाँ नहीं कर सकते। यदि वे पहले स्थान पर केवल सरणियों को अपरिवर्तनीय बनाते हैं, तो हम स्तंभन के समय को चलाने के बिना संकलन-समय प्रकार की जांच कर सकते हैं।
रेडॉन रोसबोरो

... मैंने टिप्पणियों के लिए सिर्फ पांच मिनट की संपादन अवधि की खोज की है। मेरी पहली टिप्पणी में Objectहोना चाहिए था Object[]
रेडॉन रोसबोरो

3

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

class Box<T> {

    final T x;

    Box(T x) {
        this.x = x;
    }
}

class Loophole {

    public static <T> T[] array(final T... values) {
        return (values);
    }

    public static void main(String[] args) {

        Box<String> a = new Box("Hello");
        Box<String> b = new Box("World");
        Box<String> c = new Box("!!!!!!!!!!!");
        Box<String>[] bsa = array(a, b, c);
        System.out.println("I created an array of generics.");

        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3);
        System.out.println("error not caught by array store check");

        try {
            String s = bsa[0].x;
        } catch (ClassCastException cause) {
            System.out.println("BOOM!");
            cause.printStackTrace();
        }
    }
}

आउटपुट है

I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Loophole.main(Box.java:26)

तो यह प्रतीत होता है कि आप जावा में जेनेरिक सरणी प्रकार बना सकते हैं। क्या मैंने प्रश्न को गलत समझा?


आपका उदाहरण मैंने जो पूछा है, उससे अलग है। आपने जो वर्णन किया है वह सरणी सहसंयोजक के खतरे हैं। इसे बाहर की जाँच करें। (.NET के लिए: blogs.msdn.com/b/ericlippert/archive/2007/10/17/… )
श्रद्धालुओं

उम्मीद है कि आपको संकलक से एक प्रकार की सुरक्षा चेतावनी मिलती है, हाँ?
मैट मैकहेनरी

1
हां, मुझे एक प्रकार की सुरक्षा चेतावनी मिलती है। हां, मैं देखता हूं कि मेरा उदाहरण प्रश्न के प्रति उत्तरदायी नहीं है।
एमोरी

वास्तव में आपको a, b, c के मैला होने के कारण कई बार चेतावनी मिलती है। इसके अलावा, यह अच्छी तरह से जाना जाता है और मुख्य पुस्तकालय को प्रभावित करता है, जैसे <T> java.util.Arrays.asList (T ...)। यदि आप टी के लिए किसी भी गैर-पुन: प्रयोज्य प्रकार से गुजरते हैं, तो आपको एक चेतावनी मिलती है (क्योंकि निर्मित सरणी में कोड के बहाने कम सटीक प्रकार है), और यह सुपर बदसूरत है। बेहतर होगा कि इस विधि के लेखक को चेतावनी मिल गई, बजाय उपयोग साइट पर इसे छोड़ने के, यह देखते हुए कि विधि स्वयं सुरक्षित है, यह उपयोगकर्ता के लिए सरणी को उजागर नहीं करता है।
दिमित्रिस एंड्रेउ

1
आपने यहां एक सामान्य सरणी नहीं बनाई। संकलक ने आपके लिए एक (गैर-सामान्य) सरणी बनाई।
newacct

2

मुझे पता है कि मुझे यहां पार्टी में थोड़ी देर हो गई है, लेकिन मुझे लगा कि मैं भविष्य के किसी भी googler की मदद करने में सक्षम हो सकता हूं क्योंकि इनमें से किसी ने भी मेरे मुद्दे को तय नहीं किया है। हालांकि Ferdi265 के जवाब ने काफी मदद की।

मैं अपनी खुद की लिंक्ड सूची बनाने की कोशिश कर रहा हूं, इसलिए निम्न कोड मेरे लिए काम कर रहा है:

package myList;
import java.lang.reflect.Array;

public class MyList<TYPE>  {

    private Node<TYPE> header = null;

    public void clear() {   header = null;  }

    public void add(TYPE t) {   header = new Node<TYPE>(t,header);    }

    public TYPE get(int position) {  return getNode(position).getObject();  }

    @SuppressWarnings("unchecked")
    public TYPE[] toArray() {       
        TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());        
        for(int i=0 ; i<size() ; i++)   result[i] = get(i); 
        return result;
    }


    public int size(){
         int i = 0;   
         Node<TYPE> current = header;
         while(current != null) {   
           current = current.getNext();
           i++;
        }
        return i;
    }  

InArray () विधि में मेरे लिए एक सामान्य प्रकार की एक सरणी बनाने का तरीका निहित है:

TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());    

2

मेरे मामले में, मुझे बस स्टैक की एक सरणी चाहिए थी, कुछ इस तरह:

Stack<SomeType>[] stacks = new Stack<SomeType>[2];

चूंकि यह संभव नहीं था, इसलिए मैंने निम्नलिखित को वर्कअराउंड के रूप में इस्तेमाल किया:

  1. स्टैक के आसपास एक गैर-जेनेरिक रैपर वर्ग बनाया (MyStack का कहना है)
  2. MyStack [] ढेर = नया MyStack [2] पूरी तरह से अच्छी तरह से काम किया

बदसूरत, लेकिन जावा खुश है।

नोट: ब्रेनस्ल्गस83 द्वारा प्रश्न के लिए टिप्पणी में वर्णित के अनुसार, .NET में जेनेरिक के सरणियों का होना पूरी तरह से संभव है।


2

से ओरेकल ट्यूटोरियल :

आप पैरामीटराइज्ड प्रकारों के एरेज़ नहीं बना सकते। उदाहरण के लिए, निम्नलिखित कोड संकलित नहीं करता है:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error

निम्न कोड दिखाता है कि क्या होता है जब विभिन्न प्रकार एक सरणी में डाले जाते हैं:

Object[] strings = new String[2];
strings[0] = "hi";   // OK
strings[1] = 100;    // An ArrayStoreException is thrown.

यदि आप जेनेरिक सूची के साथ एक ही चीज़ की कोशिश करते हैं, तो एक समस्या होगी:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
                                            // but the runtime can't detect it.

यदि पैरामीटर किए गए सूचियों के सरणियों की अनुमति दी गई थी, तो पिछला कोड वांछित ArrayStoreException को फेंकने में विफल होगा।

मेरे लिए, यह बहुत कमजोर लगता है। मुझे लगता है कि जेनेरिक की पर्याप्त समझ रखने वाला कोई भी व्यक्ति पूरी तरह से ठीक होगा, और यहां तक ​​कि यह भी उम्मीद करेगा कि ऐसे मामले में ArrayStoredException को फेंका नहीं जाए।


0

निश्चित रूप से इसके आसपास एक अच्छा तरीका होना चाहिए (शायद प्रतिबिंब का उपयोग करना), क्योंकि यह मुझे लगता है कि वास्तव में यही ArrayList.toArray(T[] a)करता है। मैं उद्धृत करता हूं:

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

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

तो इसके चारों ओर एक तरीका यह होगा कि आप इस फंक्शन का उपयोग करें। एक ArrayListऐसी वस्तु बनाएं , जिसे आप सरणी में चाहते हैं, फिर उपयोग करेंtoArray(T[] a) वास्तविक ऐरे को बनाने के लिए करें। यह शीघ्र नहीं होगा, लेकिन आपने अपनी आवश्यकताओं का उल्लेख नहीं किया।

तो क्या किसी को पता है कि कैसे toArray(T[] a)लागू किया जाता है?


3
List.toArray (T []) काम करता है क्योंकि आप अनिवार्य रूप से इसे रनटाइम पर घटक प्रकार T दे रहे हैं (आप इसे वांछित सरणी प्रकार का एक उदाहरण दे रहे हैं, जिससे यह सरणी वर्ग प्राप्त कर सकता है, और फिर, घटक वर्ग T )। रनटाइम पर वास्तविक घटक प्रकार के साथ, आप हमेशा रनटाइम प्रकार का उपयोग करके एक सरणी बना सकते हैं Array.newInstance()। आप पाएंगे कि कई प्रश्नों में उल्लेख किया गया है जो पूछते हैं कि संकलन समय पर अज्ञात प्रकार के साथ एक सरणी कैसे बनाएं। लेकिन ओपी विशेष रूप से पूछ रहा था कि आप new T[]वाक्यविन्यास का उपयोग क्यों नहीं कर सकते हैं , जो एक अलग सवाल है
newacct

0

ऐसा इसलिए होता है क्योंकि इसे बनाने के बाद जावा में जेनरिक मिलाया जाता है, इसलिए इसकी तरह क्लंची क्योंकि जावा के मूल निर्माताओं ने सोचा कि जब कोई सरणी बनाते हैं तो इसे बनाने में निर्दिष्ट किया जाएगा। ताकि जेनेरिक के साथ काम न करें इसलिए आपको ई [] सरणी = (ई []] नई वस्तु [१५] करनी होगी; यह संकलन करता है लेकिन यह एक चेतावनी देता है।


0

यदि हम जेनेरिक सरणियों को तुरंत नहीं दे सकते हैं, तो भाषा में सामान्य सरणी प्रकार क्यों हैं? वस्तुओं के बिना एक प्रकार होने की बात क्या है?

एकमात्र कारण जिसके बारे में मैं सोच सकता हूं, वह है - varargs - foo(T...)। अन्यथा वे पूरी तरह से जेनेरिक सरणी प्रकारों को रगड़ सकते थे। (ठीक है, वे वास्तव में varargs के लिए सरणी का उपयोग करने के लिए नहीं था, क्योंकि varargs 1.5 से पहले मौजूद नहीं था । यह शायद एक और गलती है।)

तो यह एक झूठ है, आप वैरिकाज़ के माध्यम से जेनेरिक सरणियों को तुरंत कर सकते हैं !

बेशक, जेनेरिक सरणियों के साथ समस्याएं अभी भी वास्तविक हैं, उदाहरण के लिए

static <T> T[] foo(T... args){
    return args;
}
static <T> T[] foo2(T a1, T a2){
    return foo(a1, a2);
}

public static void main(String[] args){
    String[] x2 = foo2("a", "b"); // heap pollution!
}

हम वास्तव में जेनेरिक सरणी के खतरे को प्रदर्शित करने के लिए इस उदाहरण का उपयोग कर सकते हैं ।

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

और हम foo2दावे का खंडन करने की ओर इशारा कर सकते हैं कि कल्पना हमें उन समस्याओं से दूर रखती है जो वे हमें रखने का दावा करते हैं। यदि सूर्य के पास 1.5 के लिए अधिक समय और संसाधन थे , तो मेरा मानना ​​है कि वे अधिक संतोषजनक समाधान तक पहुंच सकते थे।


0

जैसा कि दूसरों ने पहले ही उल्लेख किया है, आप निश्चित रूप से कुछ ट्रिक्स के माध्यम से बना सकते हैं ।

लेकिन यह अनुशंसित नहीं है।

क्यों कि टाइप एरेस्सर और अधिक महत्वपूर्ण रूप से covarianceएरे में जो केवल उपप्रकार एरे को एक सुपरटेप सरणी में असाइन किया जा सकता है, जो आपको रन-टाइम के कारण मान वापस लाने की कोशिश करते समय स्पष्ट टाइप कास्ट का उपयोग करने के लिए मजबूर करता है ClassCastExceptionजो मुख्य उद्देश्यों में से एक है कि जेनरिक को खत्म करने की कोशिश: संकलन के समय मजबूत प्रकार की जांच

Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException

एक अधिक प्रत्यक्ष उदाहरण प्रभावी जावा में पाया जा सकता है : आइटम 25


सहप्रसरण : प्रकार की एक सरणी S [] T का एक उपप्रकार है [] यदि S, T का उप-प्रकार है


0

यदि वर्ग एक पैरामीटर प्रकार के रूप में उपयोग करता है, तो यह टाइप T [] की एक सरणी की घोषणा कर सकता है, लेकिन यह इस तरह के सरणी को सीधे नहीं कर सकता है। इसके बजाय, एक सामान्य दृष्टिकोण वस्तु प्रकार की एक सरणी को पलटना है [], और फिर टी [] टाइप करने के लिए एक संकीर्ण डाली बनाते हैं, जैसा कि निम्नलिखित में दिखाया गया है:

  public class Portfolio<T> {
  T[] data;
 public Portfolio(int capacity) {
   data = new T[capacity];                 // illegal; compiler error
   data = (T[]) new Object[capacity];      // legal, but compiler warning
 }
 public T get(int index) { return data[index]; }
 public void set(int index, T element) { data[index] = element; }
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.