2017-10-20 64 views
5

आज, मैंने पाया कि कोई put किसी ऑब्जेक्ट में सक्षम है जो मौजूदा Map में है, भले ही ऑब्जेक्ट को सही प्रकार पर नहीं डाला जा सके।प्रारंभिक मानचित्र में असंगत प्रकार की वस्तुओं को रखना - अपेक्षित और कानूनी?

सबसे पहले, मुझे एक सरल उदाहरण के साथ शुरू करते हैं:

Map<Integer, String> myMap = new HashMap<>(); //plain old hashmap 
myMap.put(9,"star"); //no problem 

myMap.put(10, 1.2); //Incompatible type, the compiler yells 
Map<Integer, Double> aMap = (Map<Integer, Double>) myMap; //Cannot cast, the compiler yells 

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

public class NoRulesForMe { 

    static Object theRing; 

    public static void main(String[] args){ 

     Map<Integer, String> myMap = new HashMap<>(); 
     myMap.put(9,"star"); 

     Map<Integer, Double> myMapMorphed = castWildly(myMap); 
     myMapMorphed.put(99, 3.14); 

     System.out.println(myMapMorphed.get(9)); //"star", as we put in 
     System.out.println(myMapMorphed.get(99)); //3.14, as we put in 
    } 

    public static <T> T castWildly(Object value){ 
     theRing = value; 
     T morphed = (T) theRing; 
     return morphed; 
    } 
} 

मुझे आश्चर्य है कि यह एक रन-टाइम त्रुटि का कारण नहीं कर रहा हूँ: अब चलो इस पर विचार करते हैं ?

कारण मैं पूछता हूं कि मैंने उत्पादन कोड में इसका एक (अधिक शामिल) संस्करण देखा है, और मुझे आश्चर्य है, भले ही यह परेशान और सुगंधित हो, भले ही यह कार्यशीलता के अनुसार काम करने की गारंटी दी जा सके। किसी भी इनपुट की सराहना की जाएगी।

+0

आपको "टाइप एरर" Google की आवश्यकता है। –

+0

जेनिक्स के जावा के कार्यान्वयन में यह _inherent_ है। –

+0

@LouisWasserman क्या आप जावा के जेनेरिक में * क्या * अंतर्निहित हैं? मुझे आश्चर्य नहीं है कि संकलक शिकायत नहीं करता था। लेकिन बड़ा सवाल, मुझे लगता है, जावा कैसे 'डबल' को 'स्ट्रिंग' के रूप में संग्रहीत किया जा सकता है। – flow2k

उत्तर

1

इस प्रकार का कोडिंग बहुत जोखिम भरा है !! हालांकि यह संकलित होगा, आप देखेंगे कि संकलक चेतावनी के साथ शिकायत करता है:

नोट: NoRulesForMe.java अनचेक या असुरक्षित संचालन का उपयोग करता है।
नोट: एक्सक्लिंट के साथ पुन: संकलित करें: विवरण के लिए अनचेक किया गया।

ये चेतावनियां, खासकर जब से आप जेनेरिक का उपयोग कर रहे हैं, उन्हें कभी अनदेखा नहीं किया जाना चाहिए और न ही दबाया जाना चाहिए। आपको पूरी तरह से सुनिश्चित होना चाहिए (तर्कसंगत रूप से कोड का पालन करना) कि कास्ट सुरक्षित है और बाद में कुछ समस्याएं उत्पन्न नहीं कर पाएंगे। हमेशा इस तरह से कोड करना सर्वोत्तम होता है कि त्रुटियों की खोज की जाती है और रन टाइम के बजाय कंपाइलर समय पर उठाया जाता है। यहां संकलक द्वारा दी गई चेतावनी आपको बता रही है कि चीजें गलत हो सकती हैं।

आप गुजर रहे हैं अपने myMap एक Object के रूप में विधि castWildly, और जब आप को कास्ट कर रहे हैं आप Object से एक Map कास्ट कर रहे हैं।

कंपाइलर अनुमान लगा सकता है कि T आपके कोड में Map<String, Double> का प्रकार है, और इस प्रकार इसका अनुमान लगाया जा सकता है। हालांकि, कास्टिंग करते समय, इसमें कोई जानकारी नहीं है कि (उप) Object value (या Object theRing) टाइप करें। तो यह जांचने में कोई रास्ता नहीं है कि कास्ट सुरक्षित है (विशेष रूप से सुरक्षित टाइप करें)।

इस कोड के साथ समस्या तब होती है जब आप अपने मानचित्र से मूल्य पुनर्प्राप्त करते हैं। निम्नलिखित कोड में एक अतिरिक्त अतिरिक्त लाइन है, और कोड संकलित (उपरोक्त के समान चेतावनी के साथ)। ऐसा इसलिए है क्योंकि के रूप में घोषित किए गए मानचित्र से Double के रूप में एक मान को पुनर्प्राप्त करते समय संकलक टाइप करते समय पूरी तरह मान्य होता है ... रन टाइम पर, आपका कोड क्रैश हो जाएगा (नीचे दिखाए गए समय क्रैश त्रुटि को चलाएं)। कोड के लिए यह बहुत ही खतरनाक तरीका है, खासकर उत्पादन कोड में। आप चाहते हैं कि आपका कंपाइलर आपको उत्पादन कोड को तैनात करने से त्रुटियों को दे, जो संकलित करता है और आपके उत्पाद को क्रैश होने पर क्रैश करता है।

public class NoRulesForMe { 

    static Object theRing; 

    public static void main(String[] args){ 

     Map<Integer, String> myMap = new HashMap<>(); 
     myMap.put(9,"star"); 

     Map<Integer, Double> myMapMorphed = castWildly(myMap); 
     myMapMorphed.put(99, 3.14); 

     System.out.println(myMapMorphed.get(9)); //"star", as we put in 
     System.out.println(myMapMorphed.get(99)); //3.14, as we put in 

     // added to show why this style of coding causes problems 
     Double testValue1 = myMapMorphed.get(9); 
    } 

    public static <T> T castWildly(Object value){ 
     theRing = value; 
     T morphed = (T) theRing; 
     return morphed; 
    } 
} 

रन टाइम त्रुटि जब ऊपर कोड चलाने:

स्टार
3।सूत्र में 14
अपवाद "मुख्य" java.lang.ClassCastException: java.lang.String NoRulesForMe.main पर java.lang.Double में ढाला नहीं जा सकता है (NoRulesForMe.java:19)

अधिक जानकारी के लिए , जोशुआ ब्लोच द्वारा प्रभावी जावा पढ़ें; आइटम 24: अनचेक चेतावनियों को हटा दें। (यह आइटम हेडिंग जेनेरिक के तहत है)।

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