java - कक्षा चर के संबंध में अप-कास्टिंग और डाउन-कास्टिंग के बीच क्या अंतर है




casting class-variables (6)

कक्षा चर के संबंध में अप-कास्टिंग और डाउन-कास्टिंग के बीच क्या अंतर है?

उदाहरण के लिए निम्नलिखित कार्यक्रम वर्ग में पशु में केवल एक विधि होती है लेकिन कुत्ते वर्ग में दो विधियां होती हैं, फिर हम कुत्ते चर को पशु चर में कैसे डालते हैं।

यदि कास्टिंग किया जाता है तो हम कुत्ते की एक और विधि को पशु के चर के साथ कैसे बुला सकते हैं।

class Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Animal");
    }
}


class Dog extends Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Dog");
    }

    public void callme2()
    {
        System.out.println("In callme2 of Dog");
    }
}

public class UseAnimlas 
{
    public static void main (String [] args) 
    {
        Dog d = new Dog();      
        Animal a = (Animal)d;
        d.callme();
        a.callme();
        ((Dog) a).callme2();
    }
}

अपकास्टिंग का मतलब है ऑब्जेक्ट को एक सुपरटेप पर कास्टिंग करना, जबकि डाउनकास्टिंग का मतलब उप प्रकार के लिए कास्टिंग करना है।

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

इस प्रकार, लेखन

Animal a = (Animal)d;

या

Animal a = d;

बिल्कुल एक ही बिंदु की ओर जाता है और दोनों मामलों में Dog से callme() को निष्पादित किया जाएगा।

डाउनकास्टिंग आवश्यक है क्योंकि आपने पशु के उद्देश्य के रूप में परिभाषित किया a । वर्तमान में आप जानते हैं कि यह एक Dog , लेकिन जावा की इसकी कोई गारंटी नहीं है। असल में रनटाइम पर यह अलग हो सकता है और जावा ClassCastException फेंक देगा, ऐसा होगा। बेशक यह आपके बहुत नमूना उदाहरण का मामला नहीं है। यदि आप Animal को नहीं callme2() , तो जावा एप्लिकेशन को संकलित भी नहीं कर सका क्योंकि Animal में विधि callme2()

आपके उदाहरण में आप UseAnimlas से Animal UseAnimlas ( callme() के कोड तक नहीं पहुंच सकते हैं (क्योंकि Dog इसे ओवरराइट करता है) जब तक कि विधि का पालन नहीं किया जाएगा:

class Dog extends Animal 
{ 
    public void callme()
    {
        super.callme();
        System.out.println("In callme of Dog");
    }
    ... 
} 

अभिभावक: कार
बच्चा: फिगो
कार सी 1 = नया फिगो ();

=====
Upcasting: -
विधि: ऑब्जेक्ट सी 1 कक्षा के तरीकों का संदर्भ देगा (फिगो - विधि ओवरराइड किया जाना चाहिए) क्योंकि वर्ग "फिगो" को "नया" के साथ निर्दिष्ट किया गया है।
इंस्टेंस वैरिएबल: ऑब्जेक्ट सी 1 घोषणा कक्षा ("कार") के आवृत्ति चर का उल्लेख करेगा।

जब घोषणा वर्ग माता-पिता होता है और वस्तु का बच्चा बनता है तो निहित कास्टिंग होता है जो "उपक्रम" होता है।

======
Downcasting: -
फिगो एफ 1 = (फिगो) सी 1; //
विधि: ऑब्जेक्ट f1 कक्षा के विधि (figo) को संदर्भित करेगा क्योंकि प्रारंभिक ऑब्जेक्ट सी 1 वर्ग "फिगो" के साथ बनाया गया है। लेकिन एक बार नीचे कास्टिंग किया जाता है, विधियों जो केवल "फिगो" वर्ग में मौजूद हैं वे चर एफ 1 द्वारा भी संदर्भित किए जा सकते हैं।
इंस्टेंस वेरिएबल: ऑब्जेक्ट एफ 1 ऑब्जेक्ट सी 1 की घोषणा वर्ग के आवृत्ति चर का उल्लेख नहीं करेगा (सी 1 के लिए घोषणा वर्ग कार है) लेकिन डाउन कास्टिंग के साथ यह क्लास फिगो के इंस्टेंस वैरिएबल को संदर्भित करेगा।

======
उपयोग करें: जब ऑब्जेक्ट चाइल्ड क्लास और घोषणा वर्ग है, तो माता-पिता और चाइल्ड क्लास अपने स्वयं के वर्ग के इंस्टेंस वैरिएबल तक पहुंचना चाहता है, न कि माता-पिता वर्ग के, फिर इसे "डाउनकास्टिंग" के साथ किया जा सकता है।


उपक्रम और डाउनकास्टिंग जावा का महत्वपूर्ण हिस्सा है, जो हमें सरल वाक्यविन्यास का उपयोग करके जटिल प्रोग्राम बनाने की अनुमति देता है, और हमें पॉलिमॉर्फिज्म या विभिन्न ऑब्जेक्ट्स को समूहीकृत करने जैसे महान फायदे देता है। जावा किसी उप-वर्ग प्रकार के ऑब्जेक्ट को किसी सुपरक्लास प्रकार के ऑब्जेक्ट के रूप में माना जाने वाला अनुमति देता है। इसे अपकास्टिंग कहा जाता है। उपक्रम स्वचालित रूप से किया जाता है, जबकि डाउनकास्टिंग प्रोग्रामर द्वारा मैन्युअल रूप से किया जाना चाहिए , और मैं यह बताने के लिए अपना सर्वश्रेष्ठ देने जा रहा हूं कि ऐसा क्यों है।

उपक्रम और डाउनकास्टिंग एक से दूसरे तक कास्टिंग प्राइमेटिव्स की तरह नहीं हैं, और मेरा मानना ​​है कि इससे बहुत भ्रम पैदा होता है, जब प्रोग्रामर कास्टिंग ऑब्जेक्ट्स सीखना शुरू होता है।

बहुरूपता: जावा में सभी विधियां डिफ़ॉल्ट रूप से आभासी हैं। इसका मतलब है कि विरासत में उपयोग किए जाने पर किसी भी विधि को ओवरराइड किया जा सकता है, जब तक कि उस विधि को अंतिम या स्थैतिक घोषित न किया जाए

आप नीचे दिए गए उदाहरण को कैसे देख सकते हैं getType(); वस्तु (कुत्ते, पालतू, पुलिस कुत्ते) प्रकार के अनुसार काम करता है।

मान लें कि आपके पास तीन कुत्ते हैं

  1. कुत्ता - यह सुपर क्लास है।
  2. पालतू कुत्ता - पालतू कुत्ते कुत्ते को फैलाता है।
  3. पुलिस कुत्ता - पुलिस कुत्ता पालतू कुत्ता बढ़ाता है।

    public class Dog{ 
       public String getType () {
          System.out.println("NormalDog");
          return "NormalDog";
       }
     }
    
    /**
     * Pet Dog has an extra method dogName()
     */   
    public class PetDog extends Dog{ 
       public String getType () {
          System.out.println("PetDog");
          return "PetDog";
       }
       public String dogName () {
          System.out.println("I don't have Name !!");
          return "NO Name";
       }
     }
    
    /**
     * Police Dog has an extra method secretId()
     */
    public class PoliceDog extends PetDog{
    
     public String secretId() {
        System.out.println("ID");
        return "ID";
     }
    
     public String getType () {
         System.out.println("I am a Police Dog");
         return "Police Dog";
     }
    }
    

बहुरूपता: जावा में सभी विधियां डिफ़ॉल्ट रूप से आभासी हैं। इसका मतलब है कि विरासत में उपयोग किए जाने पर किसी भी विधि को ओवरराइड किया जा सकता है, जब तक कि उस विधि को अंतिम या स्थिर के रूप में घोषित नहीं किया जाता है। (वर्चुअल टेबल्स अवधारणा के अनुरूप स्पष्टीकरण)

वर्चुअल टेबल / डिस्पैच टेबल: किसी ऑब्जेक्ट की प्रेषण तालिका में ऑब्जेक्ट की गतिशील रूप से बाध्य विधियों के पते होंगे। विधि कॉल को ऑब्जेक्ट की प्रेषण तालिका से विधि का पता लाकर किया जाता है। प्रेषण तालिका एक ही कक्षा से संबंधित सभी वस्तुओं के लिए समान है, और इसलिए आम तौर पर उनके बीच साझा की जाती है।

public static void main (String[] args) {
      /**
       * Creating the different objects with super class Reference
       */
     Dog obj1 = new Dog();
`         /**
           *  Object of Pet Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry about it 
           *  
           */
     Dog obj2 = new PetDog();
`         /**
           *  Object of Police Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry       
           *  about it here even though we are extending PoliceDog with PetDog 
           *  since PetDog is extending Dog Java automatically upcast for us 
           */
      Dog obj3 = new PoliceDog();
}



 obj1.getType();

प्रिंट Normal Dog

  obj2.getType();

प्रिंट Pet Dog

 obj3.getType();

प्रिंस Police Dog

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

जब आप secretID(); का आह्वान करने का प्रयास करते हैं secretID(); obj3 पर विधि जो PoliceDog object Dog PoliceDog object लेकिन Dog को संदर्भित करता है जो पदानुक्रम में एक सुपर क्लास है, यह त्रुटि obj3 करता है क्योंकि obj3 को secretId() विधि तक पहुंच नहीं है। उस विधि को आमंत्रित करने के लिए आपको डाउनकास्ट को obj3 मैन्युअल रूप से PoliceDog करने की PoliceDog

  ( (PoliceDog)obj3).secretID();

जो ID प्रिंट करता है

dogName(); आह्वान करने के लिए इसी तरह से dogName(); PetDog क्लास में विधि आपको obj2 को PetDog को डाउनकास्ट करने की PetDog क्योंकि obj2 को Dog संदर्भ में संदर्भित किया गया है और dogName(); तक पहुंच नहीं है dogName(); तरीका

  ( (PetDog)obj2).dogName();

ऐसा क्यों है, कि उथल-पुथल स्वचालित है, लेकिन डाउनकास्टिंग मैनुअल होना चाहिए? खैर, आप देखते हैं, उतार चढ़ाव कभी असफल नहीं हो सकता है। लेकिन अगर आपके पास विभिन्न कुत्तों का एक समूह है और वे सभी को उनके प्रकार के लिए कम करना चाहते हैं, तो एक मौका है, कि इनमें से कुछ कुत्तों वास्तव में PetDog PoliceDog को फेंक कर, PoliceDog PetDog , PoliceDog और प्रक्रिया विफल हो जाते हैं।

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

नोट: यहां संदर्भ के माध्यम से इसका मतलब है कि जब आप इसे कम करते हैं तो आप अपने निष्कर्षों के मेमोरी एड्रेस को नहीं बदल रहे हैं, फिर भी यह वही रहता है जो आप उन्हें इस मामले में विशेष प्रकार के समूह में बांट रहे हैं


उपशीर्षक एक सुपरटेप पर कास्टिंग कर रहा है, जबकि डाउनकास्टिंग एक उप प्रकार के लिए कास्टिंग कर रहा है। उपक्रम को हमेशा अनुमति दी जाती है, लेकिन डाउनकास्टिंग में एक प्रकार की जांच शामिल होती है और क्लासकास्ट अपवाद को फेंक सकती है।

आपके मामले में, Dog लेकर एक Animal तक कास्ट एक उग्र है, क्योंकि Dog एक Animal । आम तौर पर, जब भी दो वर्गों के बीच संबंध होता है तो आप उग्र हो सकते हैं।

डाउनकास्टिंग कुछ ऐसा होगा:

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

असल में आप जो कर रहे हैं वह संकलक को बता रहा है कि आप जानते हैं कि ऑब्जेक्ट का रनटाइम प्रकार वास्तव में क्या है। कंपाइलर रूपांतरण की अनुमति देगा, लेकिन यह सुनिश्चित करने के लिए कि रूपांतरण रूपांतरण समझ में आता है, फिर भी रनटाइम सैनिटी चेक डालेगा। इस मामले में, कास्ट संभव है क्योंकि रनटाइम animal वास्तव में एक Dog भले ही animal का स्थिर प्रकार animal है।

हालांकि, अगर आप ऐसा करना चाहते थे:

Animal animal = new Animal();
Dog notADog = (Dog) animal;

आपको ClassCastException प्राप्त होगा। इसका कारण यह है कि animal का रनटाइम प्रकार Animal , और इसलिए जब आप रनटाइम को कास्ट करने के लिए कहते हैं तो यह देखता है कि animal वास्तव में एक Dog और इसलिए ClassCastException फेंकता है।

super.method() की विधि को कॉल करने के लिए आप super.method() या super.method() कर कर सकते हैं।

सबक्लास की विधि को कॉल करने के लिए आपको एक डाउनकास्ट करना होगा। जैसा कि ऊपर दिखाया गया है, आप आमतौर पर ClassCastException को ऐसा करके जोखिम देते हैं; हालांकि, आप कास्ट करने से पहले ऑब्जेक्ट के रनटाइम प्रकार की जांच करने के instanceof ऑपरेटर के instanceof उपयोग कर सकते हैं, जो आपको ClassCastException को रोकने की अनुमति देता है:

Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
    // Guaranteed to succeed, barring classloader shenanigans
    Dog castedDog = (Dog) animal;
}

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

  • मैन्युअल रूप से उतारने की कोई आवश्यकता नहीं है, यह स्वयं ही होता है:

    Mammal m = (Mammal)new Cat(); Mammal m = new Cat(); बराबर है Mammal m = new Cat();

  • लेकिन डाउनकास्टिंग हमेशा मैन्युअल रूप से किया जाना चाहिए:

    Cat c1 = new Cat();      
    Animal a = c1;      //automatic upcasting to Animal
    Cat c2 = (Cat) a;    //manual downcasting back to a Cat
    

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

 Cat c1 = new Cat();         
    Animal a = c1;       //upcasting to Animal
    if(a instanceof Cat){ // testing if the Animal is a Cat
        System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");        
        Cat c2 = (Cat)a;
    }

अधिक जानकारी के लिए कृपया इस आलेख को पढ़ें


शायद यह तालिका मदद करता है। कक्षा Parent या कक्षा Child के callme() विधि को कॉल करना। एक सिद्धांत के रूप में:

अपकास्टिंग -> छुपाएं

डाउनकास्टिंग -> प्रकट करना







upcasting