2009-03-19 15 views
27

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

import java.util.Map; 

public class MyClass<T> 
{ 
    public Map<String, String> getMap() 
    { 
     return null; 
    } 

    public void test() 
    { 
     MyClass<Object> success = new MyClass<Object>(); 
     String s = success.getMap().get(""); 

     MyClass unchecked = new MyClass(); 
     Map<String, String> map = unchecked.getMap(); // Unchecked warning, why? 
     String s2 = map.get(""); 

     MyClass fail = new MyClass(); 
     String s3 = fail.getMap().get(""); // Compiler error, why? 
    } 
} 

मुझे यह कंपाइलर त्रुटि मिलती है।

MyClass.java:20: incompatible types 
found : java.lang.Object 
required: java.lang.String 
       String s3 = fail.getMap().get(""); // Compiler error 
+0

अनचेक चेतावनी का सटीक पाठ क्या है? – Powerlord

+0

चेतावनी: [अनचेक] अनचेक रूपांतरण –

उत्तर

31

समझ गया। यह वास्तव में एक बग नहीं है, जैसा कि प्रतीत होता है अजीब है।

section 4.8 (raw types) of the JLS से

:

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

तो भले ही विधि के प्रकार हस्ताक्षर वर्ग के ही किसी भी प्रकार के पैरामीटर का उपयोग नहीं करता है, में प्रकार विलोपन किक और हस्ताक्षर को प्रभावी ढंग से

public Map getMap() 

दूसरे शब्दों में हो जाता है, मुझे लगता है कि आप एक सामान्य प्रकार के रूप में एक ही एपीआई के रूप में एक कच्चे प्रकार की कल्पना कर सकते हैं लेकिन सभी <X> बिट्स से (एपीआई में, कार्यान्वयन नहीं) से हटा दिए गए हैं।

संपादित करें: यह कोड:

MyClass unchecked = new MyClass(); 
Map<String, String> map = unchecked.getMap(); // Unchecked warning, why? 
String s2 = map.get(""); 

संकलित वहाँ Map<String, String> के लिए कच्चे Map प्रकार से एक अंतर्निहित लेकिन अनियंत्रित रूपांतरण है, क्योंकि। आप एक स्पष्ट रूपांतरण (जो निष्पादन समय पर कुछ नहीं करता है) बनाने पिछले मामले में से एक ही प्रभाव प्राप्त कर सकते हैं:

// Compiles, but with an unchecked warning 
String x = ((Map<String, String>)fail.getMap()).get(""); 
+1

वह बेवकूफ है। धन्यवाद जॉन! –

+2

एचएम ... यह तरह समझ में आता है ... लेकिन यह एक ही समय में अविश्वसनीय रूप से बेवकूफ है ... –

+2

मेरी राय में इतना बेवकूफ नहीं है। – alexmeia

3

एचएम ... दुर्भाग्य से मैं आपको यह नहीं बता सकता कि यह क्यों विफल रहता है। लेकिन मैं आपको एक साधारण कामकाज दे सकता हूं:

failMyClass<?> के प्रकार को बदलें, तो यह ठीक ठीक संकलित होगा।

+0

एक कास्ट ठीक काम करता है। एक प्रकार का क्यों होगा? मानचित्र के प्रकार को प्रभावित करते हैं? यह अभी भी मुझे कोई समझ नहीं आता है। –

+1

@ मोटलिन: जॉन ने इसे बहुत अच्छी तरह से समझाया: MyClass कच्चा प्रकार नहीं है। –

+0

अब मैं समझता हूं कि आपका कामकाज क्यों काम करता है, मैं इसे कास्ट के बजाय उपयोग करने जा रहा हूं। धन्यवाद। –

1

जेनेरिक प्रकार संकलन के बाद मिट जाते हैं।

जब आप ऐसा करेंगे:

Map<String, String> map = unchecked.getMap(); 

आप मानचित्र < स्ट्रिंग, स्ट्रिंग> मानचित्र से एक डाली के लिए मजबूर कर रहे हैं, और यही कारण है कि अनियंत्रित चेतावनी है। हालांकि, उस के बाद आप कर सकते हैं:

String s2 = map.get(""); 

क्योंकि मानचित्र के प्रकार के मानचित्र < स्ट्रिंग, स्ट्रिंग है>।

हालांकि

, जब आप

String s3 = fail.getMap().get(""); 

आप fail.getMap() कुछ भी करने के लिए कास्ट नहीं कर रहे, तो ठीक है के लिए स्पष्ट रूप से मानचित्र, नक्शा नहीं < स्ट्रिंग माना जाता है, स्ट्रिंग>।

String s3 = ((Map<String, String>fail.getMap()).get(""); 

जो अभी भी एक चेतावनी फेंक दिया जाएगा, लेकिन वैसे भी काम करेगा:

क्या आप बाद में क्या करना चाहिए की तरह कुछ है।

+2

फिर पहला संकलन क्यों करता है? "मिटा" यहां पूरा जवाब नहीं है। –

+0

हाँ, आप सही हैं। मुझे लगता है कि जॉन का जवाब यहां सबसे अच्छा है। – Seb

2

जॉन स्कीट द्वारा बहुत ही रोचक सवाल, और बहुत ही रोचक जवाब।

मैं सिर्फ जावा कंपाइलर के इस व्यवहार की मूर्खता या मूर्खता के बारे में कुछ जोड़ना चाहता हूं।

मुझे लगता है कि संकलक मानता है कि यदि आप जेनरसी क्लास में टाइप पैरामीटर निर्दिष्ट नहीं करते हैं तो आप सभी पर किसी भी प्रकार पैरामीटर का उपयोग नहीं कर पाएंगे (या नहीं चाहते हैं)। आप 5 से पहले जावा के संस्करण का उपयोग कर सकते हैं, या मैन्युअल रूप से कलाकारों को बनाना पसंद करते हैं।

यह मेरे लिए इतना बेवकूफ प्रतीत नहीं होता है।

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