2016-01-04 13 views
24

आज मैंने कुछ अजीब आंतरिक (गैर स्थैतिक) वर्ग व्यवहार के बारे में ठोकर खाई।आंतरिक वर्ग के अलग-अलग सदस्य व्यवहार यदि आंतरिक वर्ग बाहरी वर्ग का विस्तार करता है?

अगर मैं निम्नलिखित वर्गों है ...

class B { 
    String val = "old"; 

    void run(){ 
     val = "new"; 
     System.out.println(val);  // outputs: new 
     new InnerB().printVal();  // outputs: new 
    } 

    private class InnerB { 
     void printVal(){ System.out.println(val); } 
    } 
} 

new B().run(); 

... सब कुछ स्पष्ट हो रहा है। इनरबी का उदाहरण बी के उदाहरण से संबंधित है, इसलिए यदि इसे आउटपुट वैल होना चाहिए तो यह पहले से ही प्रतिस्थापित मूल्य 'नया' प्रिंट करता है।

लेकिन यदि आंतरिक वर्ग बाहरी वर्ग को फैलाता है तो यह काम नहीं करता है।

class B { 
    String val = "old"; 

    void run(){ 
     val = "new"; 
     System.out.println(val);  // outputs: new 
     new InnerB().printVal();  // outputs: new 
     new InheritedB().printVal(); // outputs: old new 
    } 

    private class InnerB { 
     void printVal(){ System.out.println(val); } 
    } 

    private class InheritedB extends B{ 
     void printVal(){ System.out.println(val + " "+ B.this.val); } 
    } 
} 

new B().run(); // outputs: new new old! 

अगर मैं कंस्ट्रक्टर्स मैं यह भी देखना है कि बी का एक नया उदाहरण यदि InheritedB के कहने बनाई गई है बनाया जाएगा पर एक नजर है।

मुझे यह बहुत अजीब लगता है ... क्या कोई यह समझा सकता है कि यह अंतर क्यों है?

+0

आप सुनिश्चित करें कि आप मतलब नहीं था 'InheritedB फैली InnerB' हैं? – user3707125

+0

बस मेरी मन की शांति के लिए, कृपया मुझे बताएं कि आप इसे वास्तविक कोड में करने की योजना नहीं बना रहे हैं, कि आप यह देखने के लिए बस गड़बड़ कर रहे थे कि क्या हुआ। – jpmc26

उत्तर

26

यह पंक्ति:

new InheritedB().printVal(); 

InheritedB का एक नया उदाहरण है, जिसका युक्त उदाहरण B की मौजूदा उदाहरण है बनाता है (जहां वैल "new" है)। लेकिन इस बिंदु पर वहाँ दोval चर हैं:

  • B
  • InheritedB के उदाहरण में से एक है, जो एक अलग val क्षेत्र

है की मौजूदा उदाहरण में एक दूसरे चर का मान "old" है क्योंकि यह प्रभावी रूप से फ़ील्ड का डिफ़ॉल्ट मान है।

यह बयान InheritedB में:

System.out.println(val + " "+ B.this.val); 

B से विरासत में मिली val का मूल्य बाहर प्रिंट, "युक्त उदाहरण" में val का मूल्य द्वारा पीछा किया।

यह इसके बारे में सोचने के लिए आसान हो सकता है के लिए किया जा रहा पुनर्संशोधित:

public class B 
{ 
    String val = "old"; 
} 

public class InheritedB extends B { 
    B other; 

    public InheritedB(B other) 
    { 
     this.other = other; 
    } 

    void printVal() { 
     System.out.println(val + " "+ other.val); 
    } 
} 

तो फिर तुम मूल रूप से चला रहे हैं:

B original = new B(); 
original.val = "new": 
InheritedB inherited = new InheritedB(original); 
inherited.printVal(); 

उम्मीद है कि आप का पालन कर सकते कि वास्तव में क्या देखते हो रहा है। संकलक मोटे तौर पर कि कोड में अपने मूल कोड प्रदर्शन है।

9

InheritedB में val, अपने आधार वर्ग (super.val) से val को संदर्भित करता है के बाद से है कि this का हिस्सा है।

यदि आप बाहरी वर्ग से प्राप्त नहीं हैं, val बाहरी वर्ग (B.this.scope) से दायरे को संदर्भित करता है। हालांकि, चूंकि आप वारिस करते हैं, this गुंजाइश के करीब है, और इसलिए बाहरी दायरे को छुपाता है।

जब से तुम कभी नहीं भीतरी this पर run()कहा जाता है, this.val अभी भी old है।


अगर मैं कंस्ट्रक्टर्स मैं यह भी देखना है कि बी का एक नया उदाहरण यदि InheritedB के कहने बनाई गई है बनाया जाएगा पर एक नजर है।

हां; एक व्युत्पन्न वर्ग बनाना हमेशा अपनी बेस क्लास का एक उदाहरण बनायेगा। मौजूदा उदाहरण से प्राप्त करने का कोई तरीका नहीं है।

5

InheritedB extends B के बाद से, InheritedB का उदाहरण बनाकर यह एक val विशेषता है, जो किसी भी नई बी वर्ग या उपवर्ग उदाहरण के लिए डिफ़ॉल्ट रूप से "पुराने" है प्रदान करता है।

यहाँ, InheritedB प्रिंट अपनी हीval विशेषता, नहीं संलग्नित बी उदाहरण में से एक।

4

InheritedB के मामले में val नामक दो चर हैं, B में से एक और InheritedB में से एक है। दृश्यता नियम लागू करने से मनाया गया परिणाम मिलता है।

2

अंतर InnerB में val सदस्य नहीं है। जहां वर्ग के रूप में InheritedB वर्ग बी प्रदान करता है और val सदस्य की अपनी एक प्रतिलिपि है।

void run(){ 

    val = "new";  //<--- modifies B's val not InheritedB's val 

    System.out.println(val);  // outputs: new 
    new InnerB().printVal();  // outputs: new 
    new InheritedB().printVal(); // outputs: old new 
} 

ऊपर कोड ब्लॉक में InnerB के printVal पहुँच कंटेनर की val सदस्य है, जो पहले से ही मूल्य run विधि में संशोधित किया गया था नई मूल्य।

लेकिन इनहेरिटबी के ऑब्जेक्ट में वैल की प्रतिलिपि अभी भी "पुरानी" मान, संशोधित नहीं है, और प्रिंट वैल फ़ंक्शन उस मान का उपयोग करता है।

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