जावा: (स्ट्रिंग []) List.toArray () ClassCastException देता है


107

निम्न कोड (Android में चलाएं) हमेशा मुझे 3rd लाइन में ClassCastException देता है:

final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();

यह तब भी होता है जब v2 ऑब्जेक्ट [0] होता है और जब उसमें स्ट्रिंग्स होते हैं। कोई आइडिया क्यों?


आप Covariance और Contravariance के बारे में पढ़ना चाह सकते हैं - en.wikipedia.org/wiki/…
Hut8

उस मामले के बारे में क्या जहां टी तात्कालिकता के लिए एक कारखाना विधि के साथ एक इंटरफ़ेस है।
सीबज

2
@LaceCard - यह केवल अप्रत्यक्ष रूप से सहसंयोजक / विरोधाभासी से संबंधित है। वास्तविक मुद्दा यह है कि यह toArray()विधि के निर्दिष्ट व्यवहार का प्रत्यक्ष परिणाम है ।
स्टीफन C

जवाबों:


249

ऐसा इसलिए है क्योंकि जब आप उपयोग करते हैं

 toArray() 

यह एक वस्तु देता है [], जिसे एक स्ट्रिंग पर नहीं डाला जा सकता है [] (यहां तक ​​कि सामग्री स्ट्रिंग्स हैं) ऐसा इसलिए है क्योंकि toArray विधि केवल एक हो जाती है

List 

और नहीं

List<String>

जैसा कि जेनरिक एक सोर्स कोड केवल एक चीज है, और रनटाइम पर उपलब्ध नहीं है और इसलिए यह निर्धारित नहीं कर सकता है कि किस प्रकार का सरणी बनाना है।

उपयोग

toArray(new String[v2.size()]);

जो सही प्रकार की सरणी (स्ट्रिंग [] और सही आकार का आवंटन करता है)



2
@ कालेब - सच नहीं। या कम से कम यह मूल कारण नहीं है। toArrayतरीकों से पहले संग्रह वर्गों अस्तित्व में सामान्य थे।
स्टीफन सी

10
यह सही समाधान है, लेकिन सही स्पष्टीकरण नहीं है। आप ऑब्जेक्ट [] को डबल [] नहीं कर सकते क्योंकि यह एक भाषा सुविधा है, इससे अधिक कुछ नहीं। इसका जेनरिक से कोई लेना-देना नहीं है। आप ऑब्जेक्ट को डबल मान सकते हैं कि यह वास्तव में एक डबल है। इसलिए तार्किक रूप से, आप एक सरणी के साथ भी ऐसा कर सकते हैं, लेकिन यह केवल भाषा का हिस्सा नहीं है। यदि आप ऑब्जेक्ट को डबल करते हैं तो यह सुनिश्चित करने के लिए रनटाइम चेक होगा कि वास्तव में ऑब्जेक्ट डबल है। यदि आप डबल ऑब्जेक्ट टू कास्ट करते हैं तो कोई रनटाइम चेक नहीं होता है, क्योंकि ऑब्जेक्ट डबल की विरासत पदानुक्रम में है।
काइलएम

5
IntelliJ में ऐसा करते समय, मुझे toArray(new String[0])इसके बजाय उपयोग करने के लिए एक चेतावनी मिलती है : "पुराने जावा संस्करणों में पूर्व-आकार के सरणी का उपयोग करने की सिफारिश की गई थी क्योंकि प्रतिबिंब कॉल जो उचित आकार की एक सरणी बनाने के लिए आवश्यक है, काफी धीमी थी। हालांकि ओपनजेड के देर से अपडेट के बाद से। 6 यह कॉल आंतरिक था, जो खाली सरणी संस्करण के प्रदर्शन को समान बनाता है और कभी-कभी और भी बेहतर होता है। पूर्व-आकार की सरणी को पास करना समवर्ती संग्रह के लिए खतरनाक है क्योंकि दौड़ sizeऔर toArrayकॉल के बीच दौड़ संभव है । "
माइकपोटे

35

आप गलत का उपयोग कर रहे हैं toArray()

याद रखें कि जावा की जेनरिक ज्यादातर सिंटैक्टिक शुगर है। एक ArrayList वास्तव में नहीं जानता है कि इसके सभी तत्व स्ट्रिंग्स हैं।

अपनी समस्या को ठीक करने के लिए, कॉल करें toArray(T[])। आपके मामले में,

String[] v3 = v2.toArray(new String[v2.size()]);

ध्यान दें कि सामान्य रूप toArray(T[])लौटता है T[], इसलिए परिणाम को स्पष्ट रूप से डालने की आवश्यकता नहीं है।


1
String[] v3 = v2.toArray(new String[0]); 

चाल भी करता है, ध्यान दें कि एक बार सही ArrayType विधि को दिए जाने के बाद आपको कभी भी कास्ट करने की आवश्यकता नहीं है।


0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

इस तरह का उपयोग करें।


1
कृप्या! अपना कोड फॉर्मेट करें! प्रेस में सभी का चयन करें "ctrl + k", या कोड के पहले अक्षर से पहले और अंतिम एक दूसरे पर "` "जोड़ें। उत्तर लिखते समय आप शीर्ष पर मदद में "{}" का चयन भी कर सकते हैं!
एमके
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.