अशक्त ऑपरेटर के रूप में एक इंट के रूप में अशक्त लौटना, लेकिन यदि कथन नहीं है


186

आइए निम्नलिखित स्निपेट में सरल जावा कोड को देखें:

public class Main {

    private int temp() {
        return true ? null : 0;
        // No compiler error - the compiler allows a return value of null
        // in a method signature that returns an int.
    }

    private int same() {
        if (true) {
            return null;
            // The same is not possible with if,
            // and causes a compile-time error - incompatible types.
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.temp());
        System.out.println(m.same());
    }
}

जावा कोड के इस सबसे सरल में, temp()विधि कोई संकलक त्रुटि जारी नहीं करती है भले ही फ़ंक्शन का रिटर्न प्रकार है int, और हम मूल्य null(विवरण के माध्यम से return true ? null : 0;) वापस करने की कोशिश कर रहे हैं । जब संकलित किया जाता है, तो यह स्पष्ट रूप से रन टाइम अपवाद का कारण बनता है NullPointerException

हालांकि, ऐसा प्रतीत होता है कि अगर हम एक ifकथन ( same()विधि के अनुसार) के साथ त्रैमासिक ऑपरेटर का प्रतिनिधित्व करते हैं तो वही बात गलत है , जो एक संकलन-समय त्रुटि जारी करता है ! क्यों?


6
इसके अलावा, int foo = (true ? null : 0)और new Integer(null)दोनों संकलन ठीक, दूसरा autoboxing की स्पष्ट रूप से किया जा रहा।
इज़्काता

2
समस्या @Izkata यहाँ मुझे समझने के लिए क्यों संकलक autobox की कोशिश कर रही है nullकरने के लिए Integer... कि जैसे मेरे लिए "अनुमान लगा" या "चीजों को काम करने" लगेगा ...
मार्सेलस वालेस

1
... हुह, मुझे लगा कि मेरे पास वहां एक जवाब था, जैसा कि इंटीजर कंस्ट्रक्टर (मुझे जो डॉक्स कहा गया है वह ऑटोबॉक्सिंग के लिए उपयोग किया जाता है) एक स्ट्रिंग को एक तर्क के रूप में लेने की अनुमति है (जो शून्य हो सकता है)। हालांकि, वे यह भी कहते हैं कि कंस्ट्रक्टर
संवैधानिक रूप से पारेसीआईंट

3
@ इज़काता - इंटेगर के लिए स्ट्रिंग तर्क c ऑटोरॉक्सिंग ओपेशन नहीं है। एक स्ट्रिंग एक पूर्णांक के लिए autoboxed नहीं किया जा सकता है। (फंक्शन Integer foo() { return "1"; }संकलित नहीं किया जाएगा।)
टेड हॉप

5
शांत, टर्नरी ऑपरेटर के बारे में कुछ नया सीखा!
oksayt

जवाबों:


118

संकलक nullएक के लिए एक शून्य संदर्भ के रूप में व्याख्या करता है Integer, सशर्त ऑपरेटर के लिए ऑटोबॉक्सिंग / अनबॉक्सिंग नियमों को लागू करता है (जैसा कि जावा भाषा विनिर्देश, 15.25 में वर्णित है ), और खुशी से आगे बढ़ता है। यह एक NullPointerExceptionरन टाइम उत्पन्न करेगा , जिसे आप प्रयास करके पुष्टि कर सकते हैं।


आपके द्वारा पोस्ट किए गए जावा लैंग्वेज स्पेसिफिकेशन के लिंक को देखते हुए, आपको लगता है कि ऊपर दिए गए प्रश्न के मामले में आपको कौन सा बिंदु निष्पादित होता है? पिछले एक (क्योंकि मैं अभी भी समझने की कोशिश कर रहा हूँ capture conversionऔर lub(T1,T2)) ?? इसके अलावा, क्या मुक्केबाजी को एक अशक्त मूल्य पर लागू करना वास्तव में संभव है? क्या यह "अनुमान लगाने" जैसा नहीं होगा ??
मार्सेलस वालेस

´ @ Gevorg एक अशक्त सूचक हर संभव वस्तु के लिए एक वैध सूचक है, इसलिए वहां कुछ भी बुरा नहीं हो सकता है। संकलक सिर्फ यह मानता है कि अशक्त एक पूर्णांक है जो इसे इंट करने के लिए ऑटोबॉक्स कर सकता है।
वू

1
@ गेवॉर्ग - देखें नोवाक की टिप्पणी और उनकी पोस्ट पर मेरी प्रतिक्रिया। मुझे लगता है कि उन्होंने सही क्लॉज उठाया। lub(T1,T2)T1 और T2 के पदानुक्रम में आम में सबसे विशिष्ट संदर्भ प्रकार है। (वे दोनों कम से कम ऑब्जेक्ट साझा करते हैं, इसलिए हमेशा एक सबसे विशिष्ट संदर्भ प्रकार होता है।)
टेड हॉप

8
@Gorgorg - nullएक इंटेगर में बॉक्सिंग नहीं की जाती है, इसे एक इंटीजर (एक अशक्त संदर्भ, लेकिन यह कोई समस्या नहीं है) के संदर्भ के रूप में व्याख्या की जाती है। नो इंटर्गर ऑब्जेक्ट का निर्माण नल से किया गया है, इसलिए नंबरफ़ॉर्मैट अपवाद के लिए कोई कारण नहीं है।
टेड होप

1
@Gorgorg - यदि आप बॉक्सिंग रूपांतरण के नियमों को देखते हैं , और उन्हें लागू करते हैं null(जो एक आदिम संख्यात्मक प्रकार नहीं है), तो लागू खंड "यदि p किसी अन्य प्रकार का मान है, तो बॉक्सिंग रूपांतरण पहचान रूपांतरण के बराबर है "। तो के रूपांतरण मुक्केबाजी nullके लिए Integerपैदावार null, किसी भी लागू बिना Integerनिर्माता।
टेड हॉप

40

मुझे लगता है, जावा संकलक true ? null : 0एक Integerअभिव्यक्ति के रूप में व्याख्या करता है , जिसे intसंभवतः बदलकर संभवतः दिया जा सकता है NullPointerException

दूसरे मामले के लिए, अभिव्यक्ति nullविशेष अशक्त प्रकार के दृश्य की है , इसलिए कोड return nullप्रकार को बेमेल बनाता है।


2
मुझे लगता है कि यह ऑटो-बॉक्सिंग से संबंधित है? संभवतः पहला रिटर्न जावा 5 से पहले संकलित नहीं होगा , है ना?
माइकल मैकगोवन

@ मिचेल ऐसा प्रतीत होता है यदि आप ग्रहण के अनुपालन स्तर को पूर्व -5 में सेट करते हैं।
जोनाथन फॉस्ट

@ मिचेल: यह निश्चित रूप से ऑटो-बॉक्सिंग की तरह दिखता है (मैं जावा के लिए काफी नया हूं, और अधिक परिभाषित बयान नहीं दे सकता - क्षमा करें)।
व्लाद

1
@Vlad को इंटरप्रेटिंग के true ? null : 0रूप में कैसे समाप्त किया जाएगा Integer? 0पहले ऑटोबॉक्सिंग करके ??
मार्सेलस वालेस

1
@ जॉर्ज: यहां देखें : अन्यथा, दूसरे और तीसरे ऑपरेशंस क्रमशः S1 और S2 प्रकार के हैं। बता दें कि टी 1 वह प्रकार है जो बॉक्सिंग रूपांतरण को एस 1 में लागू करने से होता है, और टी 2 उस प्रकार का होता है जो बॉक्सिंग रूपांतरण को एस 2 में लागू करने से होता है। और निम्नलिखित पाठ।
Vlad

32

दरअसल, इसके सभी जावा भाषा विनिर्देश में समझाया गया है ।

एक सशर्त अभिव्यक्ति का प्रकार निम्नानुसार निर्धारित किया जाता है:

  • यदि दूसरे और तीसरे ऑपरेंड में एक ही प्रकार है (जो शून्य प्रकार हो सकता है), तो वह सशर्त अभिव्यक्ति का प्रकार है।

इसलिए अपने में "अशक्त" (true ? null : 0)एक प्रकार का हो जाता है और फिर पूर्णांक के लिए autoboxed है।

इसे सत्यापित करने के लिए कुछ इस तरह का प्रयास करें (true ? null : null)और आपको संकलक त्रुटि मिलेगी।


3
लेकिन नियमों का वह खंड लागू नहीं होता है: दूसरे और तीसरे ऑपरेंड में एक ही प्रकार नहीं होता है।
टेड होप

1
तब उत्तर निम्नलिखित कथन में लगता है:> अन्यथा, दूसरे और तीसरे ऑपरेंड क्रमशः S1 और S2 प्रकार के होते हैं। बता दें कि टी 1 वह प्रकार है जो बॉक्सिंग रूपांतरण को एस 1 में लागू करने से होता है, और टी 2 उस प्रकार का होता है जो बॉक्सिंग रूपांतरण को एस 2 में लागू करने से होता है। सशर्त अभिव्यक्ति का प्रकार लुब (टी 1, टी 2) ()15.12.2.7) पर कब्जा रूपांतरण (.15.1.10) लागू करने का परिणाम है।
Nowaq

मुझे लगता है कि यह लागू क्लॉज है। फिर यह intफ़ंक्शन से मान वापस करने के लिए ऑटो-अनबॉक्सिंग को लागू करने का प्रयास करता है , जो एनपीई का कारण बनता है।
टेड होप

@nowaq मैंने भी यही सोचा था। हालांकि, अगर आप की कोशिश करने का स्पष्ट रूप से बॉक्स nullके Integerसाथ new Integer(null);आप एक मिलेगा "Let T1 प्रकार है कि एस 1 के लिए मुक्केबाजी रूपांतरण आवेदन करने से परिणाम ... हो" NumberFormatExceptionऔर यह स्थिति नहीं है ...
मार्सेलस वालेस

@Gorgorg मुझे लगता है कि बॉक्सिंग करते समय एक अपवाद होता है हमें यहां कोई परिणाम नहीं मिलता है। कंपाइलर सिर्फ कोड उत्पन्न करने के लिए बाध्य है जो उस परिभाषा का अनुसरण करता है जो हम करते हैं - हमें बस अपवाद मिलता है इससे पहले कि हम कर रहे हैं।
वू

25

ifबयान के मामले में , nullसंदर्भ को संदर्भ के रूप में नहीं माना जाता है Integerक्योंकि यह एक अभिव्यक्ति में भाग नहीं ले रहा है जो इसे इस तरह व्याख्या करने के लिए मजबूर करता है। इसलिए त्रुटि को संकलन-समय पर आसानी से पकड़ा जा सकता है क्योंकि यह अधिक स्पष्ट रूप से एक प्रकार की त्रुटि है।

सशर्त ऑपरेटर के लिए, जावा लैंग्वेज स्पेसिफिकेशन 515.25 "कंडिशनल ऑपरेटर ? :", नियमों में इस बात का उत्तर देता है कि रूपांतरण किस प्रकार लागू होता है:

  • यदि दूसरे और तीसरे ऑपरेंड में एक ही प्रकार है (जो अशक्त प्रकार हो सकता है), तो वह सशर्त अभिव्यक्ति का प्रकार है।

    लागू नहीं होता है क्योंकि nullनहीं है int

  • यदि दूसरे और तीसरे संचालकों में से एक प्रकार बूलियन का है और दूसरे का प्रकार बूलियन का है, तो सशर्त अभिव्यक्ति का प्रकार बूलियन है।

    लागू नहीं होता है क्योंकि न तो nullहै और न ही intहै booleanया Boolean

  • यदि दूसरे और तीसरे संचालकों में से एक अशक्त प्रकार का है और दूसरे का प्रकार एक संदर्भ प्रकार है, तो सशर्त अभिव्यक्ति का प्रकार वह संदर्भ प्रकार है।

    लागू नहीं होता है क्योंकि nullअशक्त प्रकार का है, लेकिन intएक संदर्भ प्रकार नहीं है।

  • अन्यथा, यदि दूसरे और तीसरे ऑपरेंड के प्रकार हैं जो संख्यात्मक प्रकारों के लिए परिवर्तनीय (.85.1.8) हैं, तो कई मामले हैं: […]

    लागू होता है: nullएक संख्यात्मक प्रकार के लिए परिवर्तनीय के रूप में माना जाता है, और §5.1 में परिभाषित किया गया है। 8 फेंकने के लिए "अनबॉक्सिंग रूपांतरण" NullPointerException

यदि 0ऑटोबॉक्स्ड किया जाता है, Integerतो संकलक जावा भाषा विनिर्देश में वर्णित "टर्नरी ऑपरेटर नियमों" के अंतिम मामले को निष्पादित कर रहा है। यदि यह सच है, तो मेरे लिए यह विश्वास करना कठिन है कि यह फिर उसी नियमों के 3 मामले में कूद जाएगा जो एक अशक्त और एक संदर्भ प्रकार है जो टर्नरी ऑपरेटर के रिटर्न मान को संदर्भ प्रकार (पूर्णांक) होने के नाते बनाता है। ।
मार्सेलस वालेस

@ गेवॉर्ग - यह विश्वास करना मुश्किल क्यों है कि टर्नरी ऑपरेटर एक लौट रहा है Integer? ठीक ऐसा ही हो रहा है; NPE intफ़ंक्शन से वापस लौटने के लिए अभिव्यक्ति मान को अनबॉक्स करने का प्रयास करके उत्पन्न किया जा रहा है । वापस जाने के लिए फ़ंक्शन बदलें Integerऔर यह nullबिना किसी समस्या के वापस आ जाएगा ।
टेड होप

2
@ टेडहॉप: गेवॉर्ग मेरे जवाब के पहले के संशोधन का जवाब दे रहा था, जो गलत था। आपको विसंगति को नजरअंदाज करना चाहिए।
जॉन पूर्डी

@JonPurdy "एक प्रकार को एक संख्यात्मक प्रकार के लिए परिवर्तनीय कहा जाता है यदि यह एक संख्यात्मक प्रकार है, या यह एक संदर्भ प्रकार है जिसे एक प्रकार से संख्यात्मक रूपांतरण में परिवर्तित किया जा सकता है" और मुझे नहीं लगता कि nullइस श्रेणी में आता है । इसके अलावा, हम तब "अन्यथा, बाइनरी न्यूमेरिक प्रमोशन (.25.6.2) लागू होते हैं ... ध्यान दें कि बाइनरी न्यूमेरिक प्रमोशन रिटर्न प्रकार निर्धारित करने के लिए अनबॉक्सिंग रूपांतरण (.15.1.8) ..." चरण करता है। लेकिन अनबॉक्सिंग रूपांतरण एक एनपीई उत्पन्न करेगा और यह केवल रनटाइम पर होता है न कि टर्नरी ऑपरेटर प्रकार को निर्धारित करने की कोशिश करते समय। मैं अभी भी उलझन में हूँ ..
मार्सेलस वालेस

@ जॉर्ज: अनबॉक्सिंग रनटाइम पर होता है। यह nullमाना जाता है जैसे कि यह टाइप किया गया था int, लेकिन वास्तव में इसके बराबर है throw new NullPointerException()
जॉन प्यार्डी

11

ध्यान रखने वाली पहली बात यह है कि जावा टर्नरी ऑपरेटरों के पास एक "प्रकार" है, और यह वह है जो संकलक निर्धारित करेगा और विचार करेगा कि कोई दूसरा या तीसरा पैरामीटर वास्तविक / वास्तविक प्रकार क्या है। कई कारकों के आधार पर टर्नरी ऑपरेटर प्रकार को अलग-अलग तरीकों से निर्धारित किया जाता है जैसा कि जावा भाषा विनिर्देश 15.26 में चित्रित किया गया है

उपरोक्त प्रश्न में हमें अंतिम मामले पर विचार करना चाहिए:

अन्यथा, दूसरे और तीसरे ऑपरेशंस क्रमशः S1 और S2 प्रकार के हैं। बता दें कि टी 1 वह प्रकार है जो बॉक्सिंग रूपांतरण को एस 1 में लागू करने से होता है , और टी 2 उस प्रकार का होता है जो बॉक्सिंग रूपांतरण को एस 2 में लागू करने से होता है । सशर्त अभिव्यक्ति का प्रकार लुब (टी 1, टी 2) ( ) 15.12.2.7) पर कब्जा रूपांतरण (.15.1.10) लागू करने का परिणाम है ।

जब तक आप कैप्चर कन्वर्ज़न (.105.1.10) को लागू करते हैं और लुब (T1, T2) पर सबसे अधिक नज़र डालते हैं, यह अब तक का सबसे जटिल मामला है ।

सादे अंग्रेजी में और एक चरम सरलीकरण के बाद हम दूसरे और तीसरे मापदंडों के "लिस्ट कॉमन सुपरक्लास" (हां, एलसीएम के बारे में सोचें) की गणना के रूप में इस प्रक्रिया का वर्णन कर सकते हैं। यह हमें टर्नरी ऑपरेटर "प्रकार" देगा। फिर, जो मैंने अभी कहा वह एक चरम सरलीकरण है (उन वर्गों पर विचार करें जो कई सामान्य इंटरफेस को लागू करते हैं)।

उदाहरण के लिए, यदि आप निम्नलिखित प्रयास करते हैं:

long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));

आप देखेंगे कि परिणामी प्रकार की सशर्त अभिव्यक्ति / जोड़ी java.util.Dateके लिए "Least Common Superclass" है ।TimestampTime

चूँकि nullकिसी भी चीज़ के लिए ऑटोबॉक्स्ड किया जा सकता है, "लिस्ट कॉमन सुपरक्लास" Integerक्लास है और यह ऊपर दिए गए सशर्त अभिव्यक्ति (टर्नरी ऑपरेटर) का रिटर्न प्रकार होगा। वापसी मूल्य तब एक अशक्त प्रकार का सूचक Integerहोगा और वह है जो टर्नरी ऑपरेटर द्वारा लौटाया जाएगा।

रनटाइम के समय, जब जावा वर्चुअल मशीन Integerएक NullPointerExceptionफेंक दिया जाता है। ऐसा इसलिए होता है क्योंकि जेवीएम फ़ंक्शन को लागू करने का प्रयास करता है null.intValue(), जहां nullऑटोबॉक्सिंग का परिणाम होता है।

मेरी राय में (और चूंकि मेरी राय जावा लैंग्वेज स्पेसिफिकेशन में नहीं है, वैसे भी कई लोग इसे गलत पाएंगे) कंपाइलर आपके प्रश्न में अभिव्यक्ति का मूल्यांकन करने में खराब काम करता है। यह देखते हुए कि आपने true ? param1 : param2कंपाइलर को तुरंत यह निर्धारित करना चाहिए कि पहला पैरामीटर - null- वापस कर दिया जाएगा और इसे एक कंपाइलर त्रुटि उत्पन्न करनी चाहिए। जब आप लिखते हैं तो यह कुछ इसी तरह का होता है while(true){} etc...और संकलक लूप के नीचे कोड के बारे में शिकायत करता है और इसके साथ झंडे लगाता है Unreachable Statements

आपका दूसरा मामला बहुत सीधा है और यह जवाब पहले से ही बहुत लंबा है ...;)

भूल सुधार:

एक और विश्लेषण के बाद मेरा मानना ​​है कि मैं यह कहना गलत था कि किसी nullभी चीज के लिए एक मूल्य को बॉक्सिंग / ऑटोबॉक्स किया जा सकता है। क्लास इंटेगर के बारे में बात करते हुए, स्पष्ट मुक्केबाजी में new Integer(...)कंस्ट्रक्टर को शामिल करना शामिल है या शायद Integer.valueOf(int i);(मुझे यह संस्करण कहीं मिला)। पूर्व एक फेंक देगा NumberFormatException(और ऐसा नहीं होता है), जबकि दूसरा सिर्फ एक के बाद से कोई मतलब intनहीं होगा null...


1
nullओपी के मूल कोड में बॉक्सिंग नहीं है। जिस तरह से यह काम करता है: संकलक मानता है कि यह nullएक पूर्णांक का संदर्भ है। टर्नेरी अभिव्यक्ति प्रकारों के लिए नियमों का उपयोग करना, यह तय करता है कि संपूर्ण अभिव्यक्ति एक पूर्णांक अभिव्यक्ति है। यह तब ऑटोबॉक्स में कोड उत्पन्न करता है 1(यदि स्थिति का मूल्यांकन होता है false)। निष्पादन के दौरान, स्थिति का मूल्यांकन होता है trueइसलिए अभिव्यक्ति का मूल्यांकन होता है nullintफ़ंक्शन से लौटने की कोशिश करते समय, nullअनबॉक्स किया जाता है। उसके बाद एनपीई फेंकता है। (कंपाइलर इसमें से अधिकांश का अनुकूलन कर सकता है।)
टेड होप

4

दरअसल, पहले मामले में अभिव्यक्ति का मूल्यांकन किया जा सकता है, क्योंकि कंपाइलर जानता है, कि इसका मूल्यांकन एक के रूप में किया जाना चाहिए Integer, हालांकि दूसरे मामले में रिटर्न मान ( null) का प्रकार निर्धारित नहीं किया जा सकता है, इसलिए इसे संकलित नहीं किया जा सकता है। यदि आप इसे डालते हैं Integer, तो कोड संकलन करेगा।


2
private int temp() {

    if (true) {
        Integer x = null;
        return x;// since that is fine because of unboxing then the returned value could be null
        //in other words I can say x could be null or new Integer(intValue) or a intValue
    }

    return (true ? null : 0);  //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
    //value can be Integer 
    // then null is accepted to be a variable (-refrence variable-) of Integer
}

0

इस बारे में कैसा है:

public class ConditionalExpressionType {

    public static void main(String[] args) {

        String s = "";
        s += (true ? 1 : "") instanceof Integer;
        System.out.println(s);

        String t = "";
        t += (!true ? 1 : "") instanceof String;
        System.out.println(t);

    }

}

आउटपुट सच है, सच है।

ग्रहण रंग ऑटोबॉक्सिड के रूप में सशर्त अभिव्यक्ति में 1 को कोड करता है।

मेरा अनुमान है कि संकलक ऑब्जेक्ट के रूप में अभिव्यक्ति का रिटर्न प्रकार देख रहा है।

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