जावेद कुछ असंभव जातियों को क्यों अनुमति देता है और दूसरों को नहीं?


52

अगर मैं एक कास्ट करने के लिए कोशिश Stringएक करने के लिए java.util.Date, जावा कम्पाइलर त्रुटि फैल जाती है। तो संकलक निम्न को त्रुटि के रूप में चिह्नित क्यों नहीं करता है?

List<String> strList = new ArrayList<>();                                                                      
Date d = (Date) strList;

बेशक, JVM ClassCastExceptionरनटाइम पर फेंकता है, लेकिन कंपाइलर इसे फ्लैग नहीं करता है।

व्यवहार javac 1.8.0_212 और 11.0.2 के साथ समान है।


2
यहां कुछ खास नहीं ListDate d = (Date) new Object();
इलियट फ्रिस्क

1
मैं हाल ही में एक arduino के साथ खेल रहा है। मुझे एक ऐसा कंपाइलर पसंद आएगा जिसने किसी भी कलाकार को खुशी-खुशी स्वीकार नहीं किया और फिर उन्हें पूरी तरह से अप्रत्याशित परिणामों के साथ किया। पूर्णांक के लिए स्ट्रिंग? ज़रूर! पूर्णांक के लिए डबल? जी श्रीमान! बूलियन को स्ट्रिंग? कम से कम यह कि ज्यादातर गलत हो जाता है ...
स्टियन येटेरविक

@ElliottFrisch: दिनांक और ऑब्जेक्ट के बीच एक स्पष्ट वंशानुक्रम संबंध है, लेकिन दिनांक और सूची के बीच कोई संबंध नहीं है। इसलिए मुझे उम्मीद थी कि कंपाइलर इस कास्ट को फ़्लैग करेंगे, उसी तरह यह स्ट्रींग से डेट तक कास्ट को फ्लैग करेगा। लेकिन जैसा कि ज़ुबुज़ा उनके उत्कृष्ट उत्तर में बताते हैं, सूची एक इंटरफ़ेस है, इसलिए यदि strListकोई वर्ग सूची को लागू करता है, तो कलाकार कानूनी होगा ।
माइक वोनोस्की

यह एक बार-बार आने वाला सवाल है, और मुझे यकीन है कि मैंने इसके कई डुप्लिकेट देखे हैं। यह मूल रूप से दृढ़ता से संबंधित के रिवर्स-संस्करण है: stackoverflow.com/questions/21812289/…
हल्क

1
@StianYttervik -fpermissive वह क्या कर रहा है। संकलक चेतावनी को चालू करें।
बोब्सबर्नर

जवाबों:


86

कलाकारों को तकनीकी रूप से संभव है। यह आसानी से javac द्वारा सिद्ध नहीं किया जा सकता है कि आपके मामले में ऐसा नहीं है और JLS वास्तव में इसे एक वैध जावा प्रोग्राम के रूप में परिभाषित करता है, इसलिए त्रुटि को चिह्नित करना गलत होगा।

ऐसा इसलिए है क्योंकि Listयह एक इंटरफ़ेस है। तो आपके पास एक उपवर्ग हो सकता है Dateजो वास्तव Listमें Listयहां के रूप में प्रच्छन्न है - और फिर इसे Dateपूरी तरह से ठीक होने के लिए कास्टिंग करना। उदाहरण के लिए:

public class SneakyListDate extends Date implements List<Foo> {
    ...
}

और तब:

List<Foo> list = new SneakyListDate();
Date date = (Date) list; // This one is valid, compiles and runs just fine

इस तरह के परिदृश्य का पता लगाना हमेशा संभव नहीं हो सकता है, क्योंकि यह रनटाइम जानकारी की आवश्यकता होगी यदि उदाहरण से आ रहा है, उदाहरण के लिए, इसके बजाय एक विधि। और यहां तक ​​कि अगर, यह संकलक के लिए बहुत अधिक प्रयास की आवश्यकता होगी। कंपाइलर केवल उन जातियों को रोकता है जो क्लास-ट्री के लिए बिल्कुल भी मैच नहीं होने के कारण बिल्कुल असंभव हैं। जो यहाँ नहीं है, जैसा कि देखा गया है।

ध्यान दें कि JLS को एक मान्य जावा प्रोग्राम होने के लिए आपके कोड की आवश्यकता होती है। में 5.1.6.1। अनुमत संकीर्ण रूपांतरण संदर्भ यह कहता है:

एक संकुचन संदर्भ रूपांतरण संदर्भ प्रकार से मौजूद Sसंदर्भ प्रकार के Tअगर सभी निम्न में से हैं सच :

  • [...]
  • एक निम्नलिखित मामलों के लिए लागू होता है :
    • [...]
    • Sएक इंटरफ़ेस प्रकार है, Tएक वर्ग प्रकार है, और Tएक finalवर्ग का नाम नहीं है ।

यहां तक ​​कि अगर कंपाइलर यह पता लगा सकता है कि आपका मामला वास्तव में असंभव है, तो उसे त्रुटि चिह्नित करने की अनुमति नहीं है क्योंकि जेएलएस इसे वैध जावा प्रोग्राम के रूप में परिभाषित करता है।

इसे केवल एक चेतावनी दिखाने की अनुमति होगी।


16
और ध्यान देने योग्य बात यह है कि इसका कारण स्ट्रिंग के मामले को पकड़ता है, यह है कि स्ट्रिंग अंतिम है, इसलिए कंपाइलर जानता है कि कोई भी वर्ग इसका विस्तार नहीं कर सकता है।
एमटी

5
वास्तव में, मुझे नहीं लगता कि यह स्ट्रिंग का "अंतिमपन" है जो myDate = (Date) myStringविफल हो जाता है। JLS शब्दावली का प्रयोग, बयान प्रयास से कन्वर्ट करने के लिए S( Stringकरने के लिए) T( Date)। यहाँ, Sएक इंटरफ़ेस प्रकार नहीं है, इसलिए ऊपर उद्धृत JLS शर्त लागू नहीं होती है। एक उदाहरण के रूप में, एक तिथि को कैलेंडर कास्टिंग करने का प्रयास करें और आपको एक संकलक त्रुटि मिलेगी भले ही कोई वर्ग अंतिम न हो।
माइक वोनोस्की

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

3
कंपाइलर को चेक करने से मना नहीं किया गया है। लेकिन इसे त्रुटि कहने से मना किया जाता है। यह संकलक को गैर-आज्ञाकारी बना देगा। (मेरा जवाब देखें ...)
स्टीफन सी

3
एक छोटा सा शब्दावली जोड़ने के लिए, संकलक साबित होता है कि प्रकार की आवश्यकता होगी Date & Listहै निर्जन , यह साबित होता है कि यह है पर्याप्त नहीं है निर्जन वर्तमान में (यह भविष्य में हो सकता है)।
पॉलिग्नोम

15

आइए हम आपके उदाहरण के सामान्यीकरण पर विचार करें:

List<String> strList = someMethod();       
Date d = (Date) strList;

Date d = (Date) strList;संकलन त्रुटि नहीं होने के मुख्य कारण ये हैं ।

  • सहज ज्ञान युक्त कारण है कि संकलक उद्देश्य यह है कि विधि कॉल द्वारा वापस की सटीक प्रकार नहीं (सामान्य रूप में) पता है है। यह संभव है कि एक वर्ग जो लागू करता है List, होने के अलावा , यह एक उपवर्ग भी है Date

  • तकनीकी कारण है कि जावा भाषा विशिष्टता "की अनुमति देता है" है संकुचन संदर्भ रूपांतरण है कि इस प्रकार के कलाकारों से मेल खाती है। जेएलएस 5.1.6.1 के अनुसार :

    " यदि निम्न में से सभी सत्य हैं, तो Sसंदर्भ प्रकार से संदर्भ प्रकार तक एक संकीर्ण संदर्भ रूपांतरण मौजूद Tहै:"

    ...

    5) " Sएक इंटरफ़ेस प्रकार है, Tएक वर्ग प्रकार है, और Tएक finalवर्ग का नाम नहीं है ।"

    ...

    एक अलग स्थान पर, जेएलएस का यह भी कहना है कि एक अपवाद को रनटाइम पर फेंक दिया जा सकता है ...

    ध्यान दें कि JLS 5.1.6.1 निर्धारण केवल वास्तविक रनटाइम प्रकारों के बजाय शामिल किए गए चर के घोषित प्रकारों पर आधारित है । सामान्य स्थिति में, कंपाइलर वास्तविक रनटाइम प्रकारों को नहीं जानता है और न ही कर सकता है।


तो, जावा कंपाइलर काम क्यों नहीं कर सकता है कि कलाकार काम नहीं करेगा?

  • मेरे उदाहरण में, someMethodकॉल विभिन्न प्रकारों के साथ वस्तुओं को वापस कर सकता है। यहां तक ​​कि अगर कंपाइलर विधि बॉडी का विश्लेषण करने में सक्षम था और प्रकार के सटीक सेट को निर्धारित करता था जिसे वापस किया जा सकता है, तो इसे बदलने के लिए किसी को रोकने के लिए कुछ भी नहीं है जो विभिन्न प्रकारों को वापस करने के लिए है ... कोड को कॉल करने के बाद। यही मूल कारण है कि जेएलएस 5.1.6.1 कहता है कि यह क्या कहता है।

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

तो एक स्मार्ट संकलक को यह कहने की अनुमति क्यों नहीं है कि यह वैसे भी एक त्रुटि है?

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

  • इसके अलावा, कोई भी कंपाइलर जो जावा प्रोग्राम को अस्वीकार करता है, जो जेएलएस और अन्य कंपाइलर वैध है, जावा सोर्स कोड की पोर्टेबिलिटी के लिए एक बाधा है।


4
इस तथ्य के लिए अपवोट करें कि कॉलिंग क्लास को संकलित करने के बाद, फंक्शन इम्प्लीमेंटेशन बदल सकता है , इसलिए भले ही यह संकलन के समय के योग्य हो, कैली के वर्तमान कार्यान्वयन के साथ, कि कास्ट असंभव है, यह बाद के समय में ऐसा नहीं हो सकता है जब कैली बदल गई हो या बदल दी गई हो।
पीटर -

2
पोर्टेबिलिटी समस्या को उजागर करने के लिए अपवोट करें जो एक कंपाइलर बहुत स्मार्ट होने की कोशिश करता है।
माइक वोनोस्की

2

5.5.1। संदर्भ प्रकार कास्टिंग:

एक संकलन समय संदर्भ प्रकार को देखते हुए S(स्रोत) और एक संकलन समय संदर्भ प्रकार T(लक्ष्य), एक कास्टिंग रूपांतरण से मौजूद है Sकरने के लिए Tअगर कोई संकलन समय त्रुटियों निम्नलिखित नियमों के कारण होते हैं।

[...]

यदि Sएक इंटरफ़ेस प्रकार है:

  • [...]

  • यदि Tएक वर्ग या इंटरफ़ेस प्रकार है कि अंतिम नहीं है, तो वहाँ एक महाप्रकार मौजूद रहने पर Xकी Tहै, और एक महाप्रकार Yकी S, इस तरह है कि दोनों Xऔर Yprovably अलग पैरामिट्रीकृत प्रकार के होते हैं, और इस बात का मिटाया Xऔर Yएक ही हैं, एक संकलन समय त्रुटि होता है।

    अन्यथा, कलाकार हमेशा संकलन समय पर कानूनी होता है (क्योंकि Tलागू नहीं होने पर S, Tपराक्रम का उपवर्ग )।

List<String>है Sऔर Dateहै Tआपके मामले में।

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