मैं कुछ जावा पाठ पढ़ रहा हूं और निम्नलिखित कोड मिला है:
int[] a = {4,4};
int b = 1;
a[b] = b = 0;
पाठ में, लेखक ने स्पष्ट स्पष्टीकरण नहीं दिया और अंतिम पंक्ति का प्रभाव है: a[1] = 0;
मुझे इतना यकीन नहीं है कि मैं समझता हूं: मूल्यांकन कैसे हुआ?
मैं कुछ जावा पाठ पढ़ रहा हूं और निम्नलिखित कोड मिला है:
int[] a = {4,4};
int b = 1;
a[b] = b = 0;
पाठ में, लेखक ने स्पष्ट स्पष्टीकरण नहीं दिया और अंतिम पंक्ति का प्रभाव है: a[1] = 0;
मुझे इतना यकीन नहीं है कि मैं समझता हूं: मूल्यांकन कैसे हुआ?
जवाबों:
मुझे यह स्पष्ट रूप से कहने दें, क्योंकि लोग इसे हर समय गलत समझते हैं:
सबएक्सप्रेस के मूल्यांकन का आदेश दोनों संघ और पूर्वता से स्वतंत्र है । सहकारिता और पूर्वता यह निर्धारित करती है कि ऑपरेटरों को किस क्रम में निष्पादित किया जाता है, लेकिन यह निर्धारित नहीं किया जाता है कि उप - अनुक्रमों का मूल्यांकन किस क्रम में किया जाता है। आपका प्रश्न उस आदेश के बारे में है जिसमें उप - परीक्षाओं का मूल्यांकन किया जाता है।
विचार करें A() + B() + C() * D()
। गुणन इसके अलावा की तुलना में अधिक पूर्वता है, और इसके अलावा बायां-सहयोगी है, इसलिए यह बराबर है (A() + B()) + (C() * D())
लेकिन यह जानना कि केवल आपको बताता है कि पहला जोड़ दूसरे जोड़ से पहले होगा, और यह कि गुणा दूसरे जोड़ से पहले होगा। यह आपको नहीं बताता है कि A (), B (), C () और D () किस क्रम में कहा जाएगा! (यह आपको यह भी नहीं बताता है कि गुणा पहले या बाद में होता है या नहीं।) यह इस तरह संकलित करके पूर्वता और सहानुभूति के नियमों का पालन करना पूरी तरह से संभव होगा :
d = D() // these four computations can happen in any order
b = B()
c = C()
a = A()
sum = a + b // these two computations can happen in any order
product = c * d
result = sum + product // this has to happen last
पूर्ववर्तीता और सहानुभूति के सभी नियमों का पालन किया जाता है - पहला जोड़ दूसरे जोड़ से पहले होता है, और गुणा दूसरे जोड़ से पहले होता है। स्पष्ट रूप से हम किसी भी क्रम में ए (), बी (), सी () और डी () को कॉल कर सकते हैं और अभी भी पूर्वता और सहानुभूति के नियमों का पालन कर सकते हैं!
हमें उस आदेश की व्याख्या करने के लिए असंबंधित नियम की आवश्यकता होती है , जिसमें उपप्रकारों का मूल्यांकन किया जाता है। जावा (और C #) में प्रासंगिक नियम "सबसेक्स को बाएं से दाएं मूल्यांकन किया जाता है" है। चूँकि A () C के बाईं ओर दिखाई देता है (), A () का पहले मूल्यांकन किया जाता है, इस तथ्य की परवाह किए बिना कि C () एक गुणा में शामिल है और A () केवल एक अतिरिक्त में शामिल है।
तो अब आपके पास अपने प्रश्न का उत्तर देने के लिए पर्याप्त जानकारी है। सहकारिता a[b] = b = 0
के नियमों में कहा गया है कि यह है a[b] = (b = 0);
लेकिन इसका मतलब यह नहीं है कि b=0
पहले रन! पूर्वता के नियम कहते हैं कि अनुक्रमण असाइनमेंट की तुलना में अधिक पूर्वता है, लेकिन इसका मतलब यह नहीं है कि अनुक्रमणिका सबसे सही असाइनमेंट से पहले चलती है ।
(अद्यतन: इस उत्तर के एक पुराने संस्करण में अनुभाग में कुछ छोटे और व्यावहारिक रूप से महत्वहीन चूक थे, जिन्हें मैंने सही किया है। मैंने एक ब्लॉग लेख भी लिखा है जिसमें बताया गया है कि ये नियम जावा और सी # में समझदार क्यों हैं: https: // ericlippert.com/2019/01/18/indexer-error-cases/ )
वरीयता और सहानुभूति हमें केवल यह बताती है कि शून्य का असाइनमेंट असाइनमेंट से पहलेb
होना चाहिए , क्योंकि शून्य का असाइनमेंट उस मान की गणना करता है जिसे अनुक्रमण ऑपरेशन में सौंपा गया है। पहले और बाद में मूल्यांकन किया जाता है या नहीं इसके बारे में अकेलेपन और सहानुभूति कुछ भी नहीं कहती है ।a[b]
a[b]
b=0
फिर से, यह केवल इस प्रकार है: A()[B()] = C()
- हम सभी जानते हैं कि अनुक्रमण को असाइनमेंट से पहले होना है। हम नहीं जानते कि क्या A (), B (), या C () पहले से पूर्वता और सहानुभूति के आधार पर चलता है । हमें यह बताने के लिए एक और नियम की आवश्यकता है।
नियम, फिर से, "जब आपके पास पहले क्या करना है इसके बारे में एक विकल्प है, तो हमेशा दाएं से बाएं जाएं"। हालांकि, इस विशिष्ट परिदृश्य में एक दिलचस्प शिकन है। एक थुलथुल अपवाद के साइड इफेक्ट को अशक्त संग्रह या आउट-ऑफ-रेंज इंडेक्स के कारण असाइनमेंट के बाईं ओर की गणना या असाइनमेंट की गणना का हिस्सा माना जाता है? जावा बाद को चुनता है। (बेशक, यह एक अंतर है जो केवल तब ही मायने रखता है जब कोड पहले से ही गलत है , क्योंकि सही कोड पहले से ही अशक्त नहीं करता है या खराब इंडेक्स पास नहीं करता है।)
तो क्या होता है?
a[b]
के बाईं ओर है b=0
हां, तो a[b]
रन पहले , जिसके परिणामस्वरूप a[1]
। हालाँकि, इस अनुक्रमण ऑपरेशन की वैधता की जाँच में देरी हो रही है।b=0
होता है।a
मान्य है और a[1]
सीमा में है, होता हैa[1]
अंतिम होने के लिए मान का असाइनमेंट ।इसलिए, हालांकि इस विशिष्ट मामले में उन दुर्लभ त्रुटि मामलों पर विचार करने के लिए कुछ सूक्ष्मताएं हैं जो पहली जगह में सही कोड में नहीं होनी चाहिए, सामान्य रूप से आप इसका कारण बन सकते हैं: बाईं ओर की चीजें चीजों से पहले दाईं ओर होती हैं । यही वह नियम है जिसकी आप तलाश कर रहे हैं। पूर्वगामी और सहानुभूति की बात करना भ्रामक और अप्रासंगिक दोनों है।
लोगों को यह सामान हर समय गलत लगता है , यहां तक कि उन लोगों को भी जिन्हें बेहतर पता होना चाहिए। मैंने अब तक बहुत सी प्रोग्रामिंग किताबें संपादित की हैं जो नियमों को गलत तरीके से बताती हैं, इसलिए यह कोई आश्चर्य की बात नहीं है कि बहुत से लोगों की पूर्ववर्ती / सहानुभूति और मूल्यांकन आदेश के बीच संबंध के बारे में पूरी तरह से गलत धारणाएं हैं - अर्थात्, वास्तव में ऐसा कोई संबंध नहीं है ; वे स्वतंत्र हैं।
यदि यह विषय आपकी रुचि रखता है, तो आगे पढ़ने के लिए इस विषय पर मेरे लेख देखें:
http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/
वे C # के बारे में हैं, लेकिन इनमें से अधिकांश सामान जावा पर समान रूप से लागू होते हैं।
एरिक लिपर्ट का उत्कृष्ट उत्तर फिर भी ठीक से सहायक नहीं है क्योंकि यह एक अलग भाषा के बारे में बात कर रहा है। यह जावा है, जहां जावा भाषा विनिर्देश शब्दार्थ का निश्चित विवरण है। विशेष रूप से, particular15.26.1 प्रासंगिक है क्योंकि यह =
ऑपरेटर के लिए मूल्यांकन आदेश का वर्णन करता है (हम सभी जानते हैं कि यह सही-सहयोगी है, हाँ?)। इस सवाल के बारे में परवाह करने वाले बिट्स के लिए इसे थोड़ा नीचे काटना:
यदि बाएं हाथ का ऑपरेंड एक्सप्रेशन एक एरे एक्सेस एक्सेस ( 315.13 ) है, तो कई चरणों की आवश्यकता होती है:
- सबसे पहले, बाएं हाथ के ऑपरेंड ऐरे एक्सेस एक्सप्रेशन का एरे संदर्भ सबमिशन का मूल्यांकन किया जाता है। यदि यह मूल्यांकन अचानक पूरा हो जाता है, तो असाइनमेंट की अभिव्यक्ति उसी कारण से अचानक पूरी हो जाती है; अनुक्रमणिका उपपरिवर्तन (बाएँ हाथ के ऑपरेंड एरे एक्सेस एक्सप्रेशन के) और दाएं हाथ के ऑपरेंड का मूल्यांकन नहीं किया जाता है और कोई असाइनमेंट नहीं होता है।
- अन्यथा, बाएं हाथ के ऑपरेंड ऐरे एक्सेस एक्सप्रेशन के इंडेक्स सबएक्प्रेशन का मूल्यांकन किया जाता है। यदि यह मूल्यांकन अचानक पूरा हो जाता है, तो असाइनमेंट एक्सप्रेशन उसी कारण से अचानक पूरा हो जाता है और राइट-हैंड ऑपरेंड का मूल्यांकन नहीं होता है और कोई असाइनमेंट नहीं होता है।
- अन्यथा, दाहिने हाथ के ऑपरेंड का मूल्यांकन किया जाता है। यदि यह मूल्यांकन अचानक पूरा हो जाता है, तो असाइनमेंट एक्सप्रेशन उसी कारण से अचानक पूरा हो जाता है और कोई असाइनमेंट नहीं होता है।
[... यह तब असाइनमेंट के वास्तविक अर्थ का वर्णन करता है, जिसे हम संक्षिप्तता के लिए यहाँ अनदेखा कर सकते हैं ...]
संक्षेप में, जावा में बहुत बारीकी से परिभाषित मूल्यांकन क्रम होता है जो किसी भी ऑपरेटर या विधि कॉल के तर्कों के भीतर बहुत ही बिल्कुल बाएं से दाएं होता है। सरणी असाइनमेंट अधिक जटिल मामलों में से एक है, लेकिन वहां भी यह अभी भी L2R है। (जेएलएस यह अनुशंसा करता है कि आप ऐसे कोड न लिखें जो इस प्रकार के जटिल अर्थ संबंधी अवरोधों की आवश्यकता है , और इसलिए मैं: आप प्रति कथन केवल एक असाइनमेंट के साथ पर्याप्त से अधिक परेशानी में पड़ सकते हैं!)
इस क्षेत्र में सी और सी ++ निश्चित रूप से जावा से भिन्न हैं: उनकी भाषा की परिभाषा अधिक अनुकूलन को सक्षम करने के लिए मूल्यांकन आदेश को जानबूझकर अपरिभाषित छोड़ देती है। सी # जाहिरा तौर पर जावा की तरह है, लेकिन मैं इसके साहित्य को अच्छी तरह से नहीं जानता कि औपचारिक परिभाषा को इंगित करने में सक्षम होना चाहिए। (यह वास्तव में भाषा से भिन्न होता है, हालांकि, रूबी सख्ती से L2R है, जैसा कि Tcl है - हालांकि यहां प्रासंगिक कारणों के लिए प्रति se असाइनमेंट ऑपरेटर का अभाव है - और पायथन L2R है लेकिन असाइनमेंट के संबंध में R2L है , जो मुझे अजीब लगता है, लेकिन आप वहां जाते हैं ।)
a[-1]=c
, c
मूल्यांकन किया जाता है, इससे पहले -1
कि अमान्य के रूप में मान्यता प्राप्त है।
a[b] = b = 0;
1) एरे इंडेक्सिंग ऑपरेटर में उच्चता होती है, फिर असाइनमेंट ऑपरेटर ( यह उत्तर देखें ):
(a[b]) = b = 0;
2) 15.26 के अनुसार। JLS के असाइनमेंट ऑपरेटर
12 असाइनमेंट ऑपरेटर हैं; सभी वाक्यात्मक रूप से दाएं-साहचर्य हैं (वे दाएं-बाएं समूह)। इस प्रकार, a = b = c का अर्थ है a = (b = c), जो c से b का मान प्रदान करता है और फिर b से a का मान प्रदान करता है।
(a[b]) = (b=0);
3) 15.7 के अनुसार। जेएलएस का मूल्यांकन आदेश
जावा प्रोग्रामिंग भाषा गारंटी देती है कि ऑपरेटरों के ऑपरेंड का मूल्यांकन एक विशेष मूल्यांकन क्रम में किया जाता है, अर्थात् बाएं से दाएं।
तथा
बाइनरी ऑपरेटर के बाएं हाथ के ऑपरेंड का मूल्यांकन पूरी तरह से किया जाता है, राइट-हैंड ऑपरेंड के किसी भी भाग का मूल्यांकन करने से पहले।
इसलिए:
a) (a[b])
पहले मूल्यांकन किया गयाa[1]
b) फिर (b=0)
मूल्यांकन किया गया0
ग) (a[1] = 0)
अंतिम मूल्यांकन किया गया
आपका कोड इसके बराबर है:
int[] a = {4,4};
int b = 1;
c = b;
b = 0;
a[c] = b;
जो परिणाम की व्याख्या करता है।
नीचे एक और अधिक गहराई से उदाहरण पर विचार करें।
इन प्रश्नों को हल करते समय पढ़ने के लिए ऑर्डर ऑफ प्रीएडेंस रूल्स और एसोसिएटिटी की तालिका उपलब्ध होना सबसे अच्छा है जैसे http://introcs.cs.princeton.edu/java/11precedence/
यहाँ एक अच्छा उदाहरण है:
System.out.println(3+100/10*2-13);
प्रश्न: उपरोक्त लाइन का आउटपुट क्या है?
उत्तर: वरीयता और सहकारिता के नियम लागू करें
चरण 1: पूर्वता के नियमों के अनुसार: / और * ऑपरेटर + - ऑपरेटर पर प्राथमिकता लेते हैं। इसलिए इस समीकरण को निष्पादित करने के लिए प्रारंभिक बिंदु निम्न तक सीमित होगा:
100/10*2
चरण 2: नियमों और पूर्वता के अनुसार: / और * पूर्वता में समान हैं।
जैसा कि / और * ऑपरेटर पूर्वता में समान हैं, हमें उन ऑपरेटरों के बीच की संबद्धता को देखने की जरूरत है।
इन दो विशेष परिचालकों के ASSOCIATIVITY RULES के अनुसार, हम LEFT TO RIGHT से समीकरण निष्पादित करना शुरू करते हैं अर्थात 100/10 पहले निष्पादित होता है:
100/10*2
=100/10
=10*2
=20
चरण 3: समीकरण अब निष्पादन की निम्नलिखित स्थिति में है:
=3+20-13
नियमों और पूर्वता के अनुसार: + और - पूर्वता में समान हैं।
अब हमें ऑपरेटर्स + और - ऑपरेटर्स के बीच की तालमेल को देखने की जरूरत है। इन दो विशेष संचालकों की सहानुभूति के अनुसार, हम बाएँ से दाएँ समीकरण को निष्पादित करना शुरू करते हैं अर्थात 3 + 20 को पहले निष्पादित किया जाता है:
=3+20
=23
=23-13
=10
संकलित होने पर 10 सही आउटपुट है
इन प्रश्नों को हल करते समय फिर से, ऑर्डर ऑफ प्रीएडेंस रूल्स और एसोसिएटिविटी की एक टेबल रखना महत्वपूर्ण है जैसे http://introcs.cs.princeton.edu/java/11precedence/
10 - 4 - 3
।
+
ऑपरेटर (जिसमें राइट टू लेफ्ट एसेटिविटी है), लेकिन एडिटिव + और - अभी गुणा * /% बचा है समरसता के लिए।