2013-03-08 11 views
8

निम्नलिखित उदाहरण में वास्तव में क्या होता है?एक वैरिएबल असाइन करना, वास्तव में क्या होता है, जावा

int a = 1; 
a += (a = 2); 

आउटपुट 3 है, हालांकि मैं जानना चाहता था कि कवर के तहत वास्तव में क्या होता है। उदाहरण के लिए मुझे पता है कि ब्रांड्स को + पर उच्च प्राथमिकता है इसलिए पहले (ए = 2) अभिव्यक्ति a = 2 + 2 बननी चाहिए। रनटाइम पर पहले कोष्ठक के भीतर अभिव्यक्ति निष्पादित की जानी चाहिए और फिर 2 हो जाता है। ऐसा लगता है कि a बाईं ओर +(a = 2) से पहले "लोड" हो जाता है और यह अंतिम अभिव्यक्ति पिछली लोडिंग को ओवरराइड नहीं लगती है। दूसरे शब्दों में मैं काफी उलझन में हूं कि दृश्यों के पीछे वास्तव में क्या होता है।

यदि कोई जानता है, बहुत पहले से धन्यवाद।

+1

संबंधित: http://stackoverflow.com/questions/11324850/why-swapping-integer-variable-by-xor-doesnt-work-in-a-single-line/11325458 – nhahtdh

+0

के रूप में 'पूर्णांक एक ही = 1; int tmpvar = (ए = 2); ए + = tmpvar; ' –

+0

यह 'ए = ए + (ए = 2);' में अनुवाद करता है, और ऑपरेटरों का मूल्यांकन बाएं से दाएं किया जाता है। –

उत्तर

2

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.1 से संदर्भित उदाहरण देखें, जो आपके द्वारा प्रदान किए गए उदाहरण के लगभग समान है। विशेष रूप से:

ऑपरेटर एक यौगिक-असाइनमेंट ऑपरेटर (§15.26.2), और फिर बाईं ओर संकार्य के मूल्यांकन दोनों चर कि बाएं हाथ संकार्य को दर्शाता है याद और प्राप्त करने में कठिनाई और भी शामिल है को सहेजना जो कि बाध्यकारी बाइनरी ऑपरेशन में उपयोग के लिए चर का मान है।

इस प्राथमिकता के कारण, + = का बायां हाथ पहले मूल्यांकन किया जाता है।

यह क्योंकि कोष्ठकों के आप के लिए भ्रामक हो सकता है, लेकिन कोष्ठक मूल्यांकन पर खंड पर ध्यान दें: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.7.3, और विशेष रूप से:

जावा प्रोग्रामिंग भाषा कोष्ठकों द्वारा स्पष्ट रूप से संकेत दिया मूल्यांकन के आदेश का सम्मान करता है और ऑपरेटर प्राथमिकता द्वारा स्पष्ट रूप से।

इस मामले में, + = ऑपरेटर द्वारा निर्धारित निहित प्राथमिकता इंगित करती है कि बाएं हाथ के संचालन को प्रति spec के रूप में याद किया जाएगा। हालांकि यह सच है कि असाइनमेंट ऑपरेटर, जिनमें "+ =" शामिल है, सबसे कम प्राथमिकता है, + = के लिए spec इंगित करता है कि बाएं हाथ के ऑपरेंड को 15.26.2 प्रति याद किया जाएगा।

+1

वास्तव में + = की प्राथमिकता कम से कम है और मूल्यांकन किया जाना चाहिए पिछले – Rollerball

+0

कृपया उदाहरण का पाठ पढ़ें: निम्नलिखित प्रोग्राम में, दो असाइनमेंट स्टेटमेंट्स बाएं हाथ के ऑपरेंड के मूल्य को प्राप्त और याद करते हैं, जो 9 है, अतिरिक्त ऑपरेटर के दाएं हाथ के ऑपरेशन का मूल्यांकन करने से पहले, उस बिंदु पर चर 3 पर सेट किया गया है। – Kirby

+0

यह उदाहरण आपके जैसा ही है, लेकिन विभिन्न संख्याओं के साथ। – Kirby

4

से JLS section §15.26.2 Compound Assignment Operators:

रूप E1 सेशन की एक यौगिक काम अभिव्यक्ति = E2 E1 = (टी) ((ई 1) सेशन (E2)), जहां टी प्रकार है के बराबर है ई 1 के अलावा, E1 को केवल एक बार मूल्यांकन किया जाता है।

तो अपने उदाहरण के लिए हमने:

a = (a) + (a = 2) 
अभिव्यक्ति के साथ

बाएं से दाएं का मूल्यांकन किया। इसलिए 3

+0

आपके द्वारा उद्धृत बयान मूल्यांकन के आदेश के बारे में कुछ भी नहीं कहता है। – nhahtdh

+0

@ rich.okelly ठीक है तो मूल रूप से बाएं (ए) को पूरी तरह से कोष्ठक में डाल दिया जाता है? – Rollerball

+0

@nhahtdh अनुमानित है - प्राथमिकता का क्रम कथन में आदेश देने से बकाया बकाया बयानों के साथ गारंटी देता है। –

2

के निम्नलिखित कार्यक्रम के बाईटकोड पर एक नज़र डालें:

package A; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     int a = 1; 
     a += (a = 2); 
    } 
} 

हम सिर्फ इस आदेश को चलाने के लिए की जरूरत है:

public class A.Test { 
    public A.Test(); 
    Code: 
     0: aload_0 
     1: invokespecial #1   // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_1 
     1: istore_1 
     2: iload_1 
     3: iconst_2 
     4: dup 
     5: istore_1 
     6: iadd 
     7: istore_1 
     8: return 
} 
:

javap -c Test.class 

निम्नलिखित बाईटकोड पाने के लिए


स्पष्टीकरण:

हम सिर्फ मुख्य विधि के अंदर दो पंक्तियों पर ध्यान दिया जाएगा:

int a = 1; 
a += (a = 2); 

[int a = 1; यहाँ शुरू होता है]

0: iconst_1 
  • धक्का ढेर पर 1 int ।
------------- 
|   | 
------------- 
|   | 
------------- 
|  1  | 
------------- 
    STACK 

1: istore_1 
  • पॉप पूर्णांक variable 1 के ढेर से मूल्य
------------- 
|   |    variable 1 
-------------   -------------- 
|   |   |  1  | 
-------------   -------------- 
|   | 
------------- 
    STACK 
( variable 1 a प्रतिनिधित्व करता है)

[int a = 1; खत्म यहाँ]


[a += (a = 2); यहाँ शुरू होता है]

2: iload_1 
  • स्थानीय variable 1 से एक पूर्णांक मूल्य लोड करता है और ढेर पर इसे धक्का।
------------- 
|   |    variable 1 
-------------   -------------- 
|   |   |   | 
-------------   -------------- 
|  1  | 
------------- 
    STACK 

3: iconst_2 
  • धक्का ढेर पर 2 int।
------------- 
|   |    variable 1 
-------------   -------------- 
|  2  |   |   | 
-------------   -------------- 
|  1  | 
------------- 
    STACK 

4: dup 
  • ढेर के शीर्ष पर मूल्य नकल।variable 1 के ढेर से
------------- 
|  2  |    variable 1 
-------------   -------------- 
|  2  |   |   | 
-------------   -------------- 
|  1  | 
------------- 
    STACK 

5: istore_1 
  • पॉप पूर्णांक मूल्य।
------------- 
|   |    variable 1 
-------------   -------------- 
|  2  |   |  2  | 
-------------   -------------- 
|  1  | 
------------- 
    STACK 

6: iadd 
  • एक साथ शीर्ष दो मानों को जोड़ता है। variable 1 के ढेर से
------------- 
|   |    variable 1 
-------------   -------------- 
|   |   |  2  | 
-------------   -------------- 
|  3  | 
------------- 
    STACK 

7: istore_1 
  • पॉप पूर्णांक मूल्य।
------------- 
|   |    variable 1 
-------------   -------------- 
|   |   |  3  | 
-------------   -------------- 
|   | 
------------- 
    STACK 

[a += (a = 2); खत्म यहाँ]


8: return 
  • मुख्य विधि रिटर्न।

निष्कर्ष:

a = a + (a = 2) कई आपरेशनों के माध्यम से किया जाता है। 2: iload_1 को a += (a = 2); के पहले कमांड के रूप में निष्पादित किया गया है जो समीकरण a = a + (a = 2) के पहले ऑपरेंड को पढ़ता है और ढेर पर धक्का देता है।

अगला, 3: iconst_2 और 4: dup निष्पादित किए गए हैं जो मूल रूप से int 2 स्टैक पर दो बार धक्का देते हैं; इसे a पर लोड करने के लिए और दूसरा दूसरा ऑपरेंड के रूप में लोड करने के लिए। उसके बाद, 5: istore_1 निष्पादित किया गया है जो 2a (a = 2) में लोड हो रहा है।

अंत में, 6: iadd और 7: istore_1 क्रियान्वित कर रहे हैं जहां 6: iadd पहले संकार्य और दूसरे संकार्य कहते हैं और ढेर पर परिणाम धक्का, और 7: istore_1 परिणाम है और यह भार a में दिखाई नहीं देता।


सादगी के लिए, हम इस कोड पर एक त्वरित नजर डालते हैं:

public class A.Test { 
    public A.Test(); 
    Code: 
     0: aload_0 
     1: invokespecial #1   // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_1 
     1: istore_1 
     2: iconst_3 
     3: istore_2 
     4: iload_1 
     5: iload_2 
     6: iadd 
     7: istore_1 
     8: return 
} 

आप देख सकते हैं, यह बस निम्नलिखित है:

int a = 1; 
int b = 3; 
a += b; 

और यहाँ अपने बाईटकोड है:

  • लोड 0 int01 में लोड करता है।
  • लोड 3b में लोड करता है।
  • a धक्का पर b धक्का देता है।
  • उन पर अतिरिक्त प्रदर्शन करता है और परिणाम को ढेर पर धक्का देता है।
  • स्टैक से परिणाम रोकता है और इसे a में संग्रहीत करता है।
संबंधित मुद्दे