"अमीगो, क्या तुम्हें व्हेल पसंद है?"

"व्हेल? नहीं, उनके बारे में कभी नहीं सुना।"

"यह एक गाय की तरह है, केवल बड़ा और यह तैरता है। संयोग से, व्हेल गायों से आई हैं। उह, या कम से कम वे एक सामान्य पूर्वज साझा करते हैं। इससे कोई फर्क नहीं पड़ता।"

बहुरूपता और ओवरराइडिंग - 1

"सुनो। मैं तुम्हें ओओपी के एक और बहुत शक्तिशाली उपकरण के बारे में बताना चाहता हूं: बहुरूपता । इसकी चार विशेषताएं हैं।"

1) ओवरराइडिंग विधि।

कल्पना कीजिए कि आपने एक खेल के लिए "गाय" वर्ग लिखा है। इसमें बहुत सारे सदस्य चर और विधियाँ हैं। इस वर्ग की वस्तुएँ विभिन्न कार्य कर सकती हैं: चलना, खाना, सोना। गाय जब चलती हैं तो घंटी भी बजाती हैं। मान लीजिए कि आपने कक्षा में सब कुछ छोटे से छोटे विवरण तक क्रियान्वित कर दिया है।

बहुरूपता और ओवरराइडिंग - 2

फिर अचानक ग्राहक कहता है कि वह खेल का एक नया स्तर जारी करना चाहता है, जहां सभी क्रियाएं समुद्र में होती हैं, और मुख्य पात्र एक व्हेल है।

आपने व्हेल क्लास को डिजाइन करना शुरू किया और महसूस किया कि यह काउ क्लास से थोड़ा ही अलग है। दोनों वर्ग बहुत समान तर्क का उपयोग करते हैं, और आप वंशानुक्रम का उपयोग करने का निर्णय लेते हैं।

गाय वर्ग मूल वर्ग होने के लिए आदर्श रूप से अनुकूल है: इसमें पहले से ही सभी आवश्यक चर और विधियाँ हैं। आपको बस व्हेल की तैरने की क्षमता को जोड़ना है। लेकिन एक समस्या है: आपकी व्हेल के पैर, सींग और एक घंटी है। आखिरकार, गाय वर्ग इस कार्यक्षमता को लागू करता है। आप क्या कर सकते हैं?

बहुरूपता और ओवरराइडिंग - 3

ओवरराइडिंग विधि बचाव के लिए आती है। यदि हमें एक ऐसी विधि विरासत में मिली है जो हमारी नई कक्षा में ठीक वही नहीं करती है जिसकी हमें आवश्यकता है, तो हम विधि को दूसरे के साथ बदल सकते हैं।

बहुरूपता और ओवरराइडिंग - 4

यह कैसे किया जाता है? हमारे वंशज वर्ग में, हम उस विधि की घोषणा करते हैं जिसे हम बदलना चाहते हैं (उसी विधि हस्ताक्षर के साथ जो मूल वर्ग में है) । फिर हम विधि के लिए नया कोड लिखते हैं। इतना ही। ऐसा लगता है जैसे मूल वर्ग की पुरानी पद्धति मौजूद नहीं है।

यह ऐसे काम करता है:

कोड विवरण
class Cow
{
public void printColor()
{
System.out.println("I'm white");
}
public void printName()
{
System.out.println("I'm a cow");
}
}class Whale extends Cow
{
public void printName()
{
System.out.println("I'm a whale");
}
}
यहां हम दो वर्गों को परिभाषित करते हैं:  Cow और  Whale। Whaleविरासत में मिलता है  Cow

वर्ग  विधि को Whale ओवरराइड करता है  printName();

public static void main(String[] args)
{
Cow cow = new Cow();
cow.printName();
}
यह कोड स्क्रीन पर « मैं एक गाय हूं » प्रदर्शित करता है।
public static void main(String[] args)
{
Whale whale = new Whale();
whale.printName();
}
यह कोड स्क्रीन पर « मैं व्हेल हूं » प्रदर्शित करता है

इसे इनहेरिट Cowऔर ओवरराइड करने के बाद printName, Whaleक्लास में वास्तव में निम्नलिखित डेटा और विधियाँ होती हैं:

कोड विवरण
class Whale
{
public void printColor()
{
System.out.println("I'm white");
}
public void printName()
{
System.out.println("I'm a whale");
}
}
हम किसी भी पुराने तरीके के बारे में कुछ नहीं जानते।

"ईमानदारी से, मैं यही उम्मीद कर रहा था।"

2) लेकिन यह सब नहीं है।

"मान लीजिए कि  Cow कक्षा में एक  printAll, विधि है जो दो अन्य विधियों को बुलाती है। फिर कोड इस तरह काम करेगा:"

स्क्रीन दिखाएगा:
मैं सफेद हूँ
मैं एक व्हेल हूँ

कोड विवरण
class Cow
{
public void printAll()
{
printColor();
printName();
}
public void printColor()
{
System.out.println("I'm white");
}
public void printName()
{
System.out.println("I'm a cow");
}
}

class Whale extends Cow
{
public void printName()
{
System.out.println("I'm a whale");
}
}
public static void main(String[] args)
{
Whale whale = new Whale();
whale.printAll();
}
स्क्रीन दिखाएगा:
मैं सफेद हूँ
मैं एक व्हेल हूँ

ध्यान दें कि जब व्हेल ऑब्जेक्ट पर काउ क्लास का प्रिंटऑल () मेथड कॉल किया जाता है, तो व्हेल का प्रिंटनेम () मेथड इस्तेमाल किया जाएगा, गाय का नहीं।

महत्वपूर्ण बात वह वर्ग नहीं है जिसमें विधि लिखी गई है, बल्कि उस वस्तु का प्रकार (वर्ग) है जिस पर विधि को कहा जाता है।

"अच्छा ऐसा है।"

"आप केवल गैर-स्थैतिक विधियों का उत्तराधिकारी और ओवरराइड कर सकते हैं। स्टेटिक विधियों को विरासत में नहीं मिला है और इसलिए ओवरराइड नहीं किया जा सकता है।"

इनहेरिटेंस लागू करने और विधियों को ओवरराइड करने के बाद व्हेल वर्ग कैसा दिखता है:

कोड विवरण
class Whale
{
public void printAll()
{
printColor();
printName();
}
public void printColor()
{
System.out.println("I'm white");
}
public void printName()
{
System.out.println("I'm a whale");
}
}
इनहेरिटेंस लागू करने और विधि को ओवरराइड करने के बाद व्हेल वर्ग कैसा दिखता है। हम किसी भी पुराने printNameतरीके के बारे में कुछ नहीं जानते।

3) कास्टिंग टाइप करें।

यहाँ एक और भी दिलचस्प बात है। क्योंकि एक वर्ग अपने मूल वर्ग के सभी तरीकों और डेटा को प्राप्त करता है, इस वर्ग की एक वस्तु को मूल वर्ग के चर (और माता-पिता के माता-पिता, आदि, ठीक वस्तु वर्ग तक) द्वारा संदर्भित किया जा सकता है। इस उदाहरण पर विचार करें:

कोड विवरण
public static void main(String[] args)
{
Whale whale = new Whale();
whale.printColor();
}
स्क्रीन दिखाएगा:
मैं सफेद हूँ।
public static void main(String[] args)
{
Cow cow = new Whale();
cow.printColor();
}
स्क्रीन दिखाएगा:
मैं सफेद हूँ।
public static void main(String[] args)
{
Object o = new Whale();
System.out.println(o.toString());
}
स्क्रीन दिखाएगा:
Whale@da435a।
toString() विधि ऑब्जेक्ट क्लास से विरासत में मिली है।

"अच्छी चीजें। लेकिन आपको इसकी आवश्यकता क्यों होगी?"

"यह एक मूल्यवान विशेषता है। आप बाद में समझेंगे कि यह बहुत, बहुत मूल्यवान है।"

4) लेट बाइंडिंग (डायनामिक डिस्पैच)।

यहाँ यह कैसा दिखता है:

कोड विवरण
public static void main(String[] args)
{
Whale whale = new Whale();
whale.printName();
}
स्क्रीन दिखाएगा:
मैं व्हेल हूं।
public static void main(String[] args)
{
Cow cow = new Whale();
cow.printName();
}
स्क्रीन दिखाएगा:
मैं व्हेल हूं।

ध्यान दें कि यह वेरिएबल का प्रकार नहीं है जो यह निर्धारित करता है कि हम किस विशिष्ट प्रिंटनेम पद्धति को कहते हैं (जो गाय या व्हेल वर्ग की है), बल्कि वेरिएबल द्वारा संदर्भित वस्तु का प्रकार है।

गाय चर व्हेल ऑब्जेक्ट के संदर्भ को संग्रहीत करता है , और व्हेल वर्ग में परिभाषित प्रिंटनेम विधि को कॉल किया जाएगा।

"ठीक है, उन्होंने स्पष्टता के लिए इसे नहीं जोड़ा।"

"हाँ, यह इतना स्पष्ट नहीं है। इस महत्वपूर्ण नियम को याद रखें:"

वेरिएबल पर आप जिन तरीकों को कॉल कर सकते हैं, वे वेरिएबल के प्रकार से निर्धारित होते हैं। लेकिन किस विशिष्ट विधि/कार्यान्वयन को कहा जाता है, चर द्वारा संदर्भित वस्तु के प्रकार/वर्ग द्वारा निर्धारित किया जाता है।

"मेँ कोशिश करुंगा।"

"आप इसमें लगातार दौड़ेंगे, इसलिए आप इसे जल्दी समझेंगे और कभी नहीं भूलेंगे।"

5) कास्टिंग टाइप करें।

कास्टिंग संदर्भ प्रकारों, यानी कक्षाओं के लिए अलग तरह से काम करता है, जैसे कि यह आदिम प्रकारों के लिए करता है। हालाँकि, व्यापक और संकीर्ण रूपांतरण भी संदर्भ प्रकारों पर लागू होते हैं। इस उदाहरण पर विचार करें:

व्यापक रूपांतरण विवरण
Cow cow = new Whale();

एक क्लासिक चौड़ा रूपांतरण। अब आप केवल व्हेल ऑब्जेक्ट पर काउ क्लास में परिभाषित विधियों को कॉल कर सकते हैं।

कंपाइलर आपको गाय प्रकार द्वारा परिभाषित उन विधियों को कॉल करने के लिए केवल गाय चर का उपयोग करने देगा।

संकीर्ण रूपांतरण विवरण
Cow cow = new Whale();
if (cow instanceof Whale)
{
Whale whale = (Whale) cow;
}
एक प्रकार की जाँच के साथ एक क्लासिक संकुचन रूपांतरण । गाय प्रकार का गाय चर व्हेल वस्तु के संदर्भ को संग्रहीत करता है।
हम जांच करते हैं कि यह मामला है , और फिर (चौड़ाई) प्रकार रूपांतरण करते हैं। इसे टाइप कास्टिंग भी कहते हैं ।
Cow cow = new Cow();
Whale whale = (Whale) cow; //exception
आप ऑब्जेक्ट को टाइप-चेक किए बिना संदर्भ प्रकार का संकुचित रूपांतरण भी कर सकते हैं।
इस स्थिति में, यदि गाय चर व्हेल ऑब्जेक्ट के अलावा किसी अन्य चीज़ की ओर इशारा कर रहा है, तो एक अपवाद (InvalidClassCastException) फेंका जाएगा।

6) और अब कुछ स्वादिष्ट के लिए। मूल विधि को बुला रहा है।

कभी-कभी विरासत विधि को ओवरराइड करते समय आप इसे पूरी तरह से बदलना नहीं चाहते हैं। कभी-कभी आप इसमें थोड़ा सा जोड़ना चाहते हैं।

इस मामले में, आप वास्तव में चाहते हैं कि नई विधि का कोड उसी विधि को कॉल करे, लेकिन बेस क्लास पर। और जावा आप ऐसा करते हैं। यह इस प्रकार किया जाता है:  super.method().

यहां कुछ उदाहरण दिए गए हैं:

कोड विवरण
class Cow
{
public void printAll()
{
printColor();
printName();
}
public void printColor()
{
System.out.println("I'm white");
}
public void printName()
{
System.out.println("I'm a cow");
}
}

class Whale extends Cow
{
public void printName()
{
System.out.print("This is false: ");
super.printName();

System.out.println("I'm a whale");
}
}
public static void main(String[] args)
{
Whale whale = new Whale();
whale.printAll();
}
स्क्रीन दिखाएगा:
मैं सफेद हूँ
यह झूठ है: मैं एक गाय हूँ
मैं एक व्हेल हूँ

"हम्म। खैर, वह कुछ सबक था। मेरे रोबोट के कान लगभग पिघल गए।"

"हाँ, यह सरल सामग्री नहीं है। यह सबसे कठिन सामग्री है जिसका आप सामना करेंगे। प्रोफेसर ने अन्य लेखकों से सामग्री के लिंक प्रदान करने का वादा किया, ताकि यदि आप अभी भी कुछ समझ नहीं पाते हैं, तो आप इसे भर सकते हैं। अंतराल।"