2011-04-14 15 views
14

नीचे दिए गए कोड में, पहले और दूसरे प्रिंट स्टेटमेंट्स SubObj प्रिंट कैसे करते हैं ?? उसी उप वर्ग में शीर्ष और उप बिंदु क्या करें?जावा ओवरलोडिंग और गतिशील बाध्यकारी के बारे में प्रश्न

class Top { 
    public String f(Object o) {return "Top";} 
} 

class Sub extends Top { 
    public String f(String s) {return "Sub";} 
    public String f(Object o) {return "SubObj";} 
} 

public class Test { 
    public static void main(String[] args) { 
     Sub sub = new Sub(); 
     Top top = sub; 
     String str = "Something"; 
     Object obj = str; 


     System.out.println(top.f(obj)); 
     System.out.println(top.f(str)); 
     System.out.println(sub.f(obj)); 
     System.out.println(sub.f(str)); 
    } 
} 

परिणाम से नीचे कोड रिटर्न ऊपर।

SubObj 
SubObj 
SubObj 
Sub 
+0

अब मुझे पता चला कि पहली पंक्ति कैसे काम करती है, लेकिन दूसरी पंक्ति कैसे Subobbj को प्रिंट करती है, भले ही इसमें कॉल कॉल top.f (str) जहां str स्ट्रिंग का एक प्रकार है? – user482594

+0

मैंने एक उत्तर पोस्ट किया, क्या आपने इसे देखा। यह आपके संदेहों को हल करना चाहिए। उत्तीर्ण तर्क के लिए "टाइप चेक" के बिंदु से सोचने के लिए सारांशित करें। अगर आपको यह उपयोगी लगता है तो कृपया उत्तर स्वीकार करें .. –

उत्तर

10

के बाद से आप पहले से ही मामले 1, 3 समझते हैं, और 4, के मामले से निपटने जाने 2.

(कृपया ध्यान दें - मैं कर रहा हूँ कोई JVM या compilers की अंदरूनी कामकाज पर एक विशेषज्ञ का मतलब द्वारा, लेकिन यह कैसे है मैं इसे समझता हूं। अगर कोई इसे पढ़ता है तो वह एक जेवीएम विशेषज्ञ है, तो आपको किसी भी विसंगति के इस जवाब को संपादित करने में संकोच न करें।)

एक उप-वर्ग में एक विधि जिसमें एक ही नाम है लेकिन एक अलग हस्ताक्षर विधि अधिभार के रूप में जाना जाता है । विधि अधिभार स्थिर स्थिर बाध्यकारी का उपयोग करता है, जिसका मूल रूप से मतलब है कि उचित विधि को संकलित समय पर "चुने गए" (यानी बाध्य) होने के लिए मजबूर किया जाएगा। कंपाइलर के पास आपके ऑब्जेक्ट्स के रनटाइम प्रकार (उर्फ वास्तविक प्रकार) के बारे में कोई जानकारी नहीं है।तो जब आप लिखते हैं:

      // Reference Type // Actual Type 
    Sub sub = new Sub(); // Sub    Sub 
    Top top = sub;  // Top    Sub 

कंपाइलर केवल "जानता है" शीर्ष शीर्ष प्रकार (उर्फ संदर्भ प्रकार) है। तो जब आप बाद में लिखें:

System.out.println(top.f(str)); // Prints "subobj" 

संकलक शीर्ष वर्ग के च विधि की चर्चा करते हुए के रूप में "देखता है" कॉल 'top.f'। यह "जानता है" कि str स्ट्रिंग प्रकार है जो ऑब्जेक्ट को बढ़ाता है। तो 1 से) कॉल 'top.f' शीर्ष श्रेणी की एफ विधि को संदर्भित करता है, 2) कक्षा शीर्ष में कोई एफ विधि नहीं है जो स्ट्रिंग पैरामीटर लेता है, और 3) चूंकि स्ट्र ऑब्जेक्ट का उप-वर्ग है, शीर्ष श्रेणी की f विधि संकलन समय पर एकमात्र वैध विकल्प है। तो संकलक स्पष्ट रूप से अपने मूल प्रकार, ऑब्जेक्ट को str को अपमानित करता है, इसलिए इसे शीर्ष की विधि में पारित किया जा सकता है। (यह गतिशील बाध्यकारी के विपरीत है, जहां कोड की उपरोक्त रेखा का प्रकार संकल्प को संकलक के बजाए जेवीएम द्वारा हल करने के लिए रनटाइम तक स्थगित कर दिया जाएगा।)

फिर रनटाइम पर, कोड की उपरोक्त पंक्ति में , शीर्ष पर जेवीएम द्वारा वास्तविक प्रकार, उप। हालांकि, ऑब्जेक्ट टाइप करने के लिए कंपाइलर द्वारा तर्क स्ट्र को उकसाया गया है। तो अब JVM को कक्षा उप में एक f विधि को कॉल करना है जो ऑब्जेक्ट प्रकार का पैरामीटर लेता है।

इसलिए, कोड की उपरोक्त पंक्ति "उप" के बजाय "subobj" प्रिंट करती है।

एक और बहुत समान उदाहरण के लिए, कृपया देखें: Java dynamic binding and method overriding

अद्यतन: मिले JVM की अंदरूनी कामकाज पर इस विस्तृत लेख:

http://www.artima.com/underthehood/invocationP.html

मैं इसे और अधिक स्पष्ट करने के लिए अपने कोड टिप्पणी की क्या हो रहा है:

class Top { 
    public String f(Object o) {return "Top";} 
} 

class Sub extends Top { 
    public String f(String s) {return "Sub";} // Overloading = No dynamic binding 
    public String f(Object o) {return "SubObj";} // Overriding = Dynamic binding 
} 

public class Test { 
    public static void main(String[] args) { 

            // Reference Type  Actual Type 
     Sub sub = new Sub();  // Sub    Sub 
     Top top = sub;   // Top    Sub 
     String str = "Something"; // String    String 
     Object obj = str;   // Object    String 

             // At Compile-Time:  At Run-Time: 
     // Dynamic Binding 
     System.out.println(top.f(obj)); // Top.f (Object) --> Sub.f (Object) 

     // Dynamic Binding 
     System.out.println(top.f(str)); // Top.f (Object) --> Sub.f (Object) 

     // Static Binding 
     System.out.println(sub.f(obj)); // Sub.f (Object)  Sub.f (Object) 

     // Static Binding 
     System.out.println(sub.f(str)); // Sub.f (String)  Sub.f (String) 
    } 
} 
1

हाँ, वे दोनों Sub कक्षा को इंगित करते हैं। मुद्दा यह है कि top जानता है केवल बारे में

f(Object o) 

है और यह केवल कि हस्ताक्षर कॉल कर सकते हैं।

लेकिन sub दोनों हस्ताक्षर जानता है और पैरामीटर प्रकार द्वारा चयन करना है।

6

इसका कारण यह है जावा में सभी विधि कॉल virtual हैं (डिफ़ॉल्ट रूप से)।

है, संकल्प वास्तविक वस्तु (नहीं अभिव्यक्ति की प्रकार) से शुरू होती है और (प्रति वास्तविक वस्तुओं टाइप) विरासत श्रृंखला "काम करता है" जब तक पहले मिलान विधि पाया जाता है। गैर वर्चुअल विधियां अभिव्यक्ति के प्रकार पर शुरू होंगी। (एक विधि के रूप में चिह्नित किया जा रहा final यह गैर आभासी बना देता है।)

हालांकि, सटीक तरीका हस्ताक्षर संकलन समय पर निर्धारित किया जाता है (जावा का समर्थन नहीं करता बहु प्रेषण, एकल प्रेषण केवल रन पर बदलता रहता है रिसीवर ऑब्जेक्ट के आधार पर समय) - यह बताता है कि क्यों Sub.f(String) परिणाम "सब" में हैं, उदाहरण के लिए Top.f(String)Top.f(Object) से मेल खाने वाली विधि के लिए "बाइंड" है, भले ही उप-प्रकार के शीर्ष पर आक्रमण किया गया हो। (यह संकलन समय पर निर्धारित सर्वोत्तम योग्य हस्ताक्षर था)। वर्चुअल प्रेषण स्वयं ही वही है।

हैप्पी कोडिंग।

2

इसे ऑब्जेक्ट के स्पष्ट प्रकार के साथ करना है। संकलन समय पर जावा उस प्रकार के आधार पर अपनी प्रकार की जांच करता है जिसे आप अपनी ऑब्जेक्ट को उस विशिष्ट प्रकार के बजाय घोषित करते हैं जिसे आप तुरंत चालू करते हैं।

आपके पास एक विधि f (ऑब्जेक्ट) के साथ एक प्रकार का शीर्ष है। तो जब आप कहते हैं:

System.out.println(top.f(obj)); 

जावा कम्पाइलर केवल परवाह नहीं है कि वस्तु शीर्ष के प्रकार के शीर्ष है और केवल विधि उपलब्ध एक पैरामीटर के रूप में एक वस्तु ले जाता है। रन टाइम पर यह वास्तविक तत्काल ऑब्जेक्ट की f (ऑब्जेक्ट) विधि को कॉल करता है।

अगली कॉल का अर्थ उसी तरह से किया गया है।

अगले दो कॉलों की व्याख्या की जाएगी जैसा आप उम्मीद करेंगे।

0

Sub sub = new Sub(); 
Top top = sub; 

में

आप को उप का एक उदाहरण बना दिया है, तो यह casted शीर्ष पर है, जो इसे केवल तरीकों कि शीर्ष में मौजूद के बारे में पता करता है। शीर्ष पर मौजूद विधि सार्वजनिक है String f(Object o) {return "Top";}

अब यह विधि उप द्वारा ओवरलोड हो गई है, इसलिए जब आप उप-उपक्रम का उदाहरण बनाते हैं तो उसे कॉल किया जाएगा।

एक और तरीका यह डाल करने के लिए है कि आप स्पष्ट प्रकार के रूप में

उप प्रकार मिल गया है, लेकिन शीर्ष वास्तविक प्रकार के रूप में है, क्योंकि आप सौंपा उप शीर्ष पर। यदि आप वास्तविक प्रकार को अधिभारित करते हैं तो आप विधियों को स्पष्ट प्रकार में कॉल करेंगे, लेकिन आप वास्तविक प्रकार

1

में मौजूद किसी भी विधि को कॉल करने में सक्षम नहीं होंगे, विरासत में, बेस क्लास ऑब्जेक्ट का एक उदाहरण हो सकता है व्युत्पन्न कक्षा

इस प्रकार Top top = sub; अच्छी तरह से काम करता है।

  1. System.out.println(top.f(obj)); के लिए:

    top वस्तु Sub वर्ग के f() विधि का उपयोग करने की कोशिश करता है। अब Sub कक्षा में दो f() विधि होने के कारण, पारित तर्क के लिए प्रकार की जांच की जाती है। चूंकि प्रकार Object है Sub वर्ग की विधि का आह्वान किया जाता है।

  2. System.out.println(top.f(str)); के लिए:

    आप के रूप में (1) अर्थात प्रकार एक ही व्याख्या कर सकते हैं String तो पहले f() समारोह लागू हो जाता है।

  3. System.out.println(sub.f(obj)); के लिए:

    इस रूप में आप Sub वर्ग के ही विधि बुला रहे हैं सरल है। अब चूंकि Sub वर्ग में दो अधिभारित विधि हैं, यहां भी तर्क पारित करने के लिए प्रकार की जांच की जाती है। चूंकि पारित तर्क Object प्रकार है, दूसरा f() विधि लागू हो जाती है।

  4. System.out.println(sub.f(str)); के लिए: 3 के लिए

    इसी प्रकार, यहाँ प्रकार पारित कर दिया String तो Sub कक्षा के पहले f() समारोह लागू हो जाता है।

उम्मीद है कि इससे मदद मिलती है।

+0

दूसरे के लिए, वास्तविक आउटपुट 'सबओबज' नहीं है, 'सब' – user482594

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