अच्छी तरह से यह समझने के लिए कि स्थैतिक और गतिशील बंधन कैसे वास्तव में काम करता है? या कंपाइलर और जेवीएम द्वारा उनकी पहचान कैसे की जाती है?
आइए नीचे उदाहरण लेते हैं Mammal
कि एक मूल वर्ग कहां है जिसमें एक विधि है speak()
और Human
कक्षा फैली हुई है Mammal
, speak()
विधि को ओवरराइड करती है और फिर से इसे ओवरलोड करती है speak(String language)
।
public class OverridingInternalExample {
private static class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
private static class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
// Valid overload of speak
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
@Override
public String toString() { return "Human Class"; }
}
// Code below contains the output and bytecode of the method calls
public static void main(String[] args) {
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
}
}
जब हम उपर्युक्त कोड संकलित करते हैं और उपयोग करके बायटेकोड को देखने का प्रयास करते हैं javap -verbose OverridingInternalExample
, तो हम देख सकते हैं कि कंपाइलर एक स्थिर तालिका बनाता है जहां यह प्रोग्राम के लिए हर विधि कॉल और बाइट कोड को पूर्णांक कोड प्रदान करता है जिसे मैंने निकाला है और कार्यक्रम में ही शामिल किया है ( हर विधि कॉल के नीचे टिप्पणी देखें)
ऊपर दिए गए कोड को देख कर हम इस बात का bytecodes देख सकते हैं humanMammal.speak()
, human.speak()
और human.speak("Hindi")
पूरी तरह से अलग कर रहे हैं ( invokevirtual #4
, invokevirtual #7
, invokevirtual #9
) क्योंकि संकलक तर्क सूची और वर्ग संदर्भ के आधार पर उन दोनों के बीच अंतर करने के लिए सक्षम है। क्योंकि यह सब संकलित समय पर संवैधानिक रूप से हल हो जाता है यही कारण है कि मेथड ओवरलोडिंग को स्टेटिक पॉलीमॉर्फिज़्म या स्टेटिक बाइंडिंग के रूप में जाना जाता है ।
लेकिन बायटेकोड के लिए anyMammal.speak()
और humanMammal.speak()
समान ( invokevirtual #4
) है क्योंकि कंपाइलर के अनुसार दोनों तरीकों को कहा जाता हैMammal
संदर्भ ।
तो अब सवाल आता है कि अगर दोनों मेथड कॉल में एक ही बाईटेकोड हो तो जेवीएम को किस तरीके से कॉल करना है?
खैर, इसका जवाब बाइटकोड में ही छिपा है और यह invokevirtual
इंस्ट्रक्शन सेट है। JVM का उपयोग करता हैinvokevirtual
जावा को C ++ वर्चुअल मेथड के बराबर करने के लिए निर्देश । C ++ में यदि हम किसी अन्य कक्षा में एक विधि को ओवरराइड करना चाहते हैं, तो हमें उसे आभासी घोषित करने की आवश्यकता है, लेकिन जावा में, सभी विधियां डिफ़ॉल्ट रूप से आभासी हैं, क्योंकि हम चाइल्ड क्लास (निजी, अंतिम और स्थिर तरीकों को छोड़कर) में हर विधि को ओवरराइड कर सकते हैं।
जावा में, प्रत्येक संदर्भ चर में दो छिपे हुए बिंदु होते हैं
- तालिका के लिए एक पॉइंटर जो फिर से ऑब्जेक्ट के तरीके और क्लास ऑब्जेक्ट के लिए एक पॉइंटर रखता है। जैसे [बोलो (), बोलो (स्ट्रिंग) कक्षा वस्तु]
- उस ऑब्जेक्ट के डेटा के लिए ढेर पर आवंटित मेमोरी के लिए एक पॉइंटर जैसे उदाहरण चर के मान।
तो सभी ऑब्जेक्ट रेफरेंस अप्रत्यक्ष रूप से एक टेबल के संदर्भ को रखते हैं, जो उस ऑब्जेक्ट के सभी विधि संदर्भों को रखता है। जावा ने इस अवधारणा को C ++ से उधार लिया है और इस तालिका को वर्चुअल टेबल (vtable) के रूप में जाना जाता है।
एक विएबेट संरचना की तरह एक सरणी है जो वर्चुअल तरीकों के नाम और सरणी सूचकांकों पर उनके संदर्भ रखती है। JVM प्रति वर्ग केवल एक व्यवहार्य बनाता है जब वह कक्षा को मेमोरी में लोड करता है।
इसलिए जब भी जेवीएम एक invokevirtual
निर्देश सेट के साथ मुठभेड़ करता है, तो वह विधि संदर्भ के लिए उस वर्ग की व्यवहार्यता की जांच करता है और उस विशिष्ट विधि को आमंत्रित करता है जो हमारे मामले में संदर्भ से नहीं एक वस्तु से विधि है।
क्योंकि यह सब केवल रनटाइम पर हल हो जाता है और रनटाइम में JVM को पता चल जाता है कि किस विधि को लागू करना है, इसीलिए मेथड ओवरराइडिंग को गतिशील बहुरूपता या बस बहुरूपता या गतिशील बंधन के रूप में जाना जाता है ।
आप इसे मेरे लेख पर अधिक विवरण कैसे पढ़ सकते हैं JVM हैंडल मेथड ओवरलोडिंग और आंतरिक रूप से ओवरराइडिंग ।