2012-06-25 34 views
14
public class Test2 { 

    public static void main(String[] args) { 
     Test2 obj=new Test2(); 
     String a=obj.go(); 

     System.out.print(a); 
    } 


    public String go() { 
     String q="hii"; 
     try { 
      return q; 
     } 
     finally { 
      q="hello"; 
      System.out.println("finally value of q is "+q); 
     } 
    } 

फ़ंक्शन go() से लौटने के बाद यह प्रिंटिंग hii क्यों है, अंत में ब्लॉक में मान "हैलो" में बदल गया है?अजीब अंततः व्यवहार?

कार्यक्रम के उत्पादन

finally value of q is hello 
hii 
+1

आप इसे पढ़ना चाहेंगे: http://stackoverflow.com/questions/65035/in-java-does-return-trump-finally –

+2

स्थानीय चर 'q' का मान बदलकर "हैलो" कर दिया गया है, हाँ। लेकिन आप जो लौटाया वह था "एचआईआई"। – maksimov

+0

कृपया मेरा नया उत्तर देखें ... आइए इस अवधारणा को और अधिक परिशोधित करने का प्रयास करें .. – Ahmad

उत्तर

27

क्योंकि आप एक मूल्य है कि q से मूल्यांकित किया गया था इससे पहले कि आप अंत में ब्लॉक में q का मान परिवर्तित लौटे है यही कारण है। आपने q लौटाया, जिसने इसका मूल्य मूल्यांकन किया; तो आपने finally ब्लॉक में q को बदल दिया, जिसने लोड किए गए मान को प्रभावित नहीं किया; फिर मूल्यांकन मूल्य का उपयोग कर वापसी पूरी हो गई।

इस तरह की मुश्किल कोड न लिखें। अगर यह उस व्यक्ति को भ्रमित करता है जिसने इसे लिखा है, तो अगली लड़के के कारण होने वाली समस्याओं की कल्पना करें, जब आप कहीं और हों तो ट्रैक के नीचे कुछ साल।

+0

लेकिन आखिरकार ब्लॉक निष्पादित होने के बाद मान वापस आ जाता है .. इसलिए – Harinder

+1

@ डेनिस अंततः ब्लॉक को निष्पादित करने से पहले लोड करने का मूल्य लोड किया गया था। मैंने पहले ही कहा है। – EJP

+1

@ डेनिस हां, लेकिन 'अंत में' आप पहले से ही 'वापसी' निर्देश _past_ पहले ही नहीं हैं, इससे पहले नहीं। – maksimov

0

[ईजेपी से टिप्पणी के बाद संपादित, मेरी पहली प्रतिक्रिया ने प्रश्न का उत्तर नहीं दिया और यह भी गलत था।]
अब मेरा जवाब सही समझा जाना चाहिए कि कोशिश ब्लॉक के रूप में और आखिरकार ब्लॉक सामान्य रूप से पूरा हो जाता है q को वापस कर दिया जाता है। और कारण "एचआईआई" मान वापस आ गया है ईजेपी उत्तर में समझाया गया है। मैं अभी भी जेएलएस में एक स्पष्टीकरण की तलाश में हूं।

JLS 14.20.2 Execution of try-catch-finally

पर एक नज़र एक अंत में ब्लॉक के साथ एक कोशिश बयान पहली कोशिश ब्लॉक को क्रियान्वित करते हुए निष्पादित किया जाता है है। तो फिर वहाँ एक विकल्प है:

कोशिश ब्लॉक के निष्पादन सामान्य रूप से पूरा करता है, तो अंत में ब्लॉक निष्पादित किया जाता है, और फिर वहाँ एक विकल्प है:
अंत में ब्लॉक सामान्य रूप से पूरा करता है, तो कोशिश बयान सामान्य रूप से पूरा करती है।
[...]

और JLS 14.17 The return Statement

एक अभिव्यक्ति के साथ एक वापसी कथन विधि जिसमें यह है की invoker को नियंत्रण हस्तांतरण करने के लिए प्रयास करता है; अभिव्यक्ति का मूल्य विधि आमंत्रण का मूल्य बन जाता है। अधिक सटीक रूप से, इस तरह के एक रिटर्न स्टेटमेंट का निष्पादन पहले अभिव्यक्ति का मूल्यांकन करता है। यदि किसी कारण से अभिव्यक्ति का मूल्यांकन अचानक समाप्त हो जाता है, तो उस कारण के लिए वापसी विवरण अचानक समाप्त हो जाता है। अभिव्यक्ति के मूल्यांकन सामान्य रूप से पूर्ण करता है, एक मूल्य के वी उत्पादन, तो वापसी कथन अचानक पूरा करता है, कारण मूल्य वी के साथ एक वापसी

और किया जा रहा है:

पूर्ववर्ती वर्णन कहते हैं कि "हस्तांतरण करने के लिए प्रयास करता है नियंत्रण "केवल" स्थानांतरण नियंत्रण "के बजाय" क्योंकि यदि कोई विधि या कन्स्ट्रक्टर के भीतर कोई प्रयास कथन (§14.20) है, जिसका प्रयास ब्लॉक में रिटर्न स्टेटमेंट होता है, तो आखिर में उन प्रयासों के खंडों के खंडों को निष्पादित किया जाएगा, क्रमशः, बाहरी, नियंत्रण से पहले विधि या कन्स्ट्रक्टर के आवेदक को स्थानांतरित कर दिया जाता है। आखिरकार खंड के पूर्ण होने से रिटर्न स्टेटमेंट द्वारा शुरू किए गए नियंत्रण के हस्तांतरण में बाधा आ सकती है।

+1

यह सवाल का जवाब कैसे देता है? – EJP

+0

अभी भी सवाल का जवाब नहीं देता है। 'क्यू' * वापस नहीं * वापस आ गया है। क्यू का मान जब रिटर्न स्टेटमेंट निष्पादित किया गया था * वापस कर दिया गया है। – EJP

4

return रिटर्न मूल्य का संदर्भ नहीं। return q;catch में निष्पादित हो जाता है q का वर्तमान मान इसके परिणाम के रूप में विधि द्वारा कैश किया जाता है। तो अगर finally ब्लॉक में भी आप q को नए मान के साथ फिर से सौंपेंगे, यह विधि द्वारा पहले से कैश किए गए मान को प्रभावित नहीं करता है।

आप मूल्य जो वापस आ जाना चाहिए आप की तरह

} finally { 
    q = "hello"; 
    System.out.println("finally value of q is " + q); 

    return q;//here you set other value in return 
} 

दिए गए मान को प्रभावित करने का अन्य तरीका है अपने finally ब्लॉक में एक और return का उपयोग करना होगा अपडेट करना चाहते हैं राज्य कैश की गई वस्तु का बदलकर है। उदाहरण के लिए यदि qList था तो हम इसमें नया तत्व जोड़ सकते थे (लेकिन ध्यान दें कि बदलते राज्य एक नए उदाहरण को पुन: असाइन करने जैसा नहीं है, जैसे हम final चर बदल सकते हैं, लेकिन हम इसे फिर से सौंप नहीं सकते हैं)।

} finally { 
    q.add(new Element); //this will place new element (update) in List 
    //object stored by return because it is same object from q reference 
    System.out.println("finally value of q is " + q); 
} 
+0

'मान से (ऑब्जेक्ट) + संदर्भ से, सटीक संदर्भ नहीं', 'संदर्भ से पढ़ें/संग्रह ऑब्जेक्ट', और 'बदले में संग्रहीत ऑब्जेक्ट' व्यर्थ हैं। कोई जवाब नहीं यहां शायद बाहर निकलने के लिए संघर्ष करने का एक जवाब है, लेकिन शब्दावली इतनी उलझन में है कि इसका कोई मतलब नहीं बताया गया है। – EJP

2

अंत में वापसी के बाद लेकिन विधि वास्तव में फोन करने वाले रिटर्न से पहले निष्पादित करता है। यह फेंकने के समान है। यह फेंकने के बाद और ब्लॉक से बाहर निकलने से पहले होता है। परिवर्तनीय क्यू पढ़कर रिटर्न वैल्यू पहले से ही कुछ रजिस्टर में सेट है। यदि क्यू उत्परिवर्तनीय था, तो आप अंत में इसे बदल सकते हैं और आप कॉलर में उस परिवर्तन को देखेंगे। यह इस तरह से क्यों काम करता है? एक के लिए, यह शायद लागू करने के लिए कम से कम जटिल है। दो, यह आपको अधिकतम लचीलापन देता है। आप एक स्पष्ट वापसी के साथ अंत में वापसी मूल्य को ओवरराइड कर सकते हैं। डिफ़ॉल्ट रूप से इसे संरक्षित करने से आप या तो व्यवहार चुन सकते हैं।

0

स्ट्रिंग के बजाय स्ट्रिंगबफर का उपयोग करने का प्रयास करें और आपको परिवर्तन दिखाई देगा .... ऐसा लगता है कि रिटर्न स्टेटमेंट उस वस्तु को अवरुद्ध करता है जिसे वापस किया जाना है और संदर्भ नहीं। तुम भी की hashCode मुद्रण कर इसकी पुष्टि करने के लिए कोशिश कर सकते: में जाने()

  • वस्तु से लौटाए जाने

    • वस्तु अंत में
    • वस्तु मुख्य()

      public static void से मुद्रित किया जा रहा (String [] args) {

      Test obj=new Test(); 
           StringBuffer a=obj.go(); 
           System.out.print(a); 
          } 
          public StringBuffer go() { 
           StringBuffer q=new StringBuffer("hii"); 
           try { 
            return q; 
           } 
           finally { 
            q=q.append("hello"); 
            System.out.println("finally value of q is "+q); 
           } 
          } 
      
  • +0

    'उस ऑब्जेक्ट को ब्लॉक करता है जिसे वापस किया जाना है' व्यर्थ है। कोई जवाब नहीं – EJP

    -1

    ठीक है, क्या मैंने पाया है इस प्रकार,

    वापसी वास्तव में एक मान देता है और उसके String a=obj.go(); में कॉपी किया जाता है, इससे पहले कि निष्पादन अंत में को जाता है।

    प्रयोगों का पालन करके इसे सत्यापित करने दें।

    public class Test2 { 
    
        public static void main(String[] args) { 
        Test2 obj=new Test2(); 
        String a=obj.go(); 
    
        System.out.print(a); 
        } 
    
    
        public String go() { 
        String q="hii"; 
        try { 
         return q; 
        } 
        finally { 
         q="hello"; 
         System.out.println("finally value of q is "+q); 
        } 
    } 
    

    कार्यक्रम के उत्पादन

    अंत में क्ष का मूल्य हैलो

    hii

    है और अगर हम स्ट्रिंग के बजाय StringBuffer ले इस प्रकार है,

    public class Test2 { 
    
        public static void main(String[] args) { 
         // TODO Auto-generated method stub 
    
         Test2 obj=new Test2(); 
         StringBuffer a=obj.go(); 
    
         System.out.print(a); 
        } 
    
    
        public StringBuffer go(){ 
         StringBuffer q=new StringBuffer("hii"); 
         try{ 
    
          return q; 
         } 
         finally{ 
    
          q.replace(0, q.length(), "hello"); 
          System.out.println("finally value of q is "+q); 
          /*return q1;*/ 
    
         } 
    
        } 
    } 
    

    उत्पादन comesout होने के लिए,

    अंत में क्ष का मूल्य हैलो

    हैलो

    और अंत में अगर हम पूर्णांक स्ट्रिंग के बजाय लेने के लिए इस प्रकार है,

    public class Test2 { 
    
        public static void main(String[] args) { 
         // TODO Auto-generated method stub 
    
         Test2 obj=new Test2(); 
         int a=obj.go(); 
    
         System.out.print(a); 
        } 
    
    
        public int go(){ 
         int q=1; 
         try{ 
    
          return q; 
         } 
         finally{ 
    
          q=2; 
          System.out.println("finally value of q is "+q); 
          /*return q1;*/ 
    
         } 
    
        } 
    } 
    

    उत्पादन

    अंत में क्ष का मूल्य है 2

           **Ananlysis** 
    

    1.In पहला मामला है, स्ट्रिंग की प्रतिलिपि बनाई पता लौट चर एक, तो निष्पादन में अंत में जाता है जहां स्ट्रिंग बदल जाती है। लेकिन स्ट्रिंग्स के मामले में, हम किसी भी स्ट्रिंग का उपयोग नहीं कर सकते हैं, एक नया स्ट्रिंग बनाया गया है। तो परिवर्तनीय में मूल स्ट्रिंग का पता सहेजा गया है, जो मुद्रित हो जाता है।

    2.In दूसरे मामले, चर एक में StringBuffer की प्रतिलिपि बनाई पता वापस, और में अंत में इस StringBuffer वस्तु हेरफेर किया है, बल्कि नया बनाने। तो वैरिएबल में संग्रहीत मूल्य भी छेड़छाड़ हो जाता है, जो प्रिंट स्टेटमेंट में देखा जाता है।

    3. तीसरे मामले में, int के मूल्य को अंततः निष्पादन से पहले में प्रतिलिपि बनाई गई है। और इस प्रकार का मान 1 हो जाता है और अंततः हमने q का मान बदल दिया है जो का मूल्य बदलता नहीं है।

    +0

    काफी सही .. आपने अपना जवाब नहीं पढ़ा ... – Ahmad

    +0

    आपके पहले दो उदाहरण दोनों अप्रासंगिक हैं। पहला वाला सिर्फ सादा गलत कोड है, क्योंकि String.repace() मान को म्यूटेट नहीं करता है, यह एक नया लौटाता है जिसे आप फेंक रहे हैं। दूसरा दूसरा मान को बदलता है, लेकिन जैसा कि ओपी नहीं कर रहा है, मैं इस बिंदु को देखने में विफल रहता हूं। तीसरा व्यक्ति सिर्फ दोहराता है कि ओपी क्या पूछ रहा है, और जो उत्तर पहले ही दिया गया है उसे दोहराता है। – EJP

    0

    आखिरकार ब्लॉक क्या है?

    -By definition from Java "अंत में अवरोध ब्लॉक हमेशा बाहर निकलने पर निष्पादित करता है। यह सुनिश्चित करता है कि आखिरकार ब्लॉक को निष्पादित किया जाता है भले ही एक अप्रत्याशित अपवाद होता है।"

    तो, यह प्रिंट करता है "जैसे ही यह क्यू का हैलो है" जैसे ही यह कोशिश ब्लॉक है और System.out.print (a) पर जाता है; और विधि() द्वारा लौटाए गए मान को मुद्रित करता है।

    यदि आपके पास नेटबीन या ग्रहण जैसे डिबगर्स हैं, तो इसका विश्लेषण ब्रेक पॉइंट को रखने और कोड के माध्यम से जागने के द्वारा किया जा सकता है।

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