जावा में डाउनकास्टिंग


179

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

संकलित त्रुटि को एक कास्ट जोड़कर हटाया जा सकता है, लेकिन वैसे भी रनटाइम पर टूट जाएगा।

इस स्थिति में, जावा डाउनकास्टिंग की अनुमति देता है यदि इसे रनटाइम पर निष्पादित नहीं किया जा सकता है?
क्या इस अवधारणा का कोई व्यावहारिक उपयोग है?

public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, 
                         // but runtime exception - java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}

9
कोड का एक उदाहरण स्निपेट प्लस त्रुटि उन लोगों के लिए एक बेहतर प्रश्न होगा जो अवधारणाओं को सीखने की कोशिश कर रहे हैं।
बॉब क्रॉस

3
बॉब की टिप्पणी के लिए +1। सवाल बिल्कुल स्पष्ट नहीं है।
जॉन स्कीट

मुझे लगता है कि ऊपर दिए गए उदाहरण velocityreviews.com/forums/t151266-downcasting-problem.html से लिए गए हैं, जिनके कुछ अच्छे उत्तर पहले से ही हैं।
फीलो

2
@PhiLho - जोएल का मुख्य उद्देश्य एक ही आम छतरी के नीचे सभी महान प्रश्न और उत्तर प्राप्त करना था। इससे कोई फर्क नहीं पड़ता कि प्रश्न / कोड / उत्तर पहले से ही कुछ अन्य साइटों में पोस्ट किए गए हैं। मुझे आशा है कि आप इस बिंदु को प्राप्त करेंगे, अन्यथा जोएल के पॉडकास्ट को सुनें।
सर्वव्यापी

कृपया इसे संपादित करें ताकि कोड स्निपेट सभी चार स्थानों द्वारा इंडेंट हों। वह स्वरूपण ठीक कर देगा।
स्लिम

जवाबों:


298

डाउनकास्टिंग की अनुमति तब दी जाती है जब संभावना है कि यह रन टाइम पर सफल हो:

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

कुछ मामलों में यह सफल नहीं होगा:

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

जब एक कास्ट (जैसे कि यह अंतिम एक) रनटाइम में विफल रहता ClassCastExceptionहै तो फेंक दिया जाएगा।

अन्य मामलों में यह काम करेगा:

Object o = "a String";
String s = (String) o; // this will work, since o references a String

ध्यान दें कि कुछ कलाकारों का संकलन समय पर बंद कर दिया जाएगा, क्योंकि वे कभी भी सफल नहीं होंगे:

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.

Object o = new Object(); String s = (String) o;यह मेरे लिए ठीक काम कर रहा है ..: ओ कैसे?
आसिफ मुश्ताक

@UnKnown: ऐसा नहीं होना चाहिए। डबल चेक जो आपने वास्तव में संकलित किया और उस संस्करण को चलाया और यदि आप अभी भी इसे पुन: उत्पन्न कर सकते हैं, तो एक अलग प्रश्न ( एसएससीसीई के साथ ) पोस्ट करें।
जोआचिम सॉउर

@JoachimSauer उस संस्करण से आपका क्या मतलब है? मैं जावा 8 का उपयोग कर रहा हूं
आसिफ मुश्ताक

1
@UnKnown: मेरा मतलब है कि आपके द्वारा पोस्ट किया गया कोड नहीं चलना चाहिए (यह संकलन करेगा, लेकिन रनटाइम पर एक अपवाद फेंक देगा)। ये टिप्पणियां डीबग करने का स्थान नहीं हैं। कृपया एक अलग प्रश्न पोस्ट करें।
जोकिम सॉयर

रनिंग के समय कास्टिंग कैसे विफल हो जाती है? शून्य के लिए लक्ष्य वस्तु संदर्भ सेट करता है? एक अपवाद फेंकता है?
साइग्नसएक्स 1

17

अपने उदाहरण का उपयोग करते हुए, आप कर सकते हैं:

public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}

मैंने सिर्फ उदाहरण के महत्व को सीखा जब मेरा सार वर्ग कई वर्गों द्वारा बढ़ाया जा रहा था और मैं सार वर्ग प्रकार का उल्लेख करते हुए उन वर्गों के अनन्य तरीकों का उपयोग करना चाहता था। Instof का उपयोग न करने से मेरे पास वर्ग का अपवाद था
तरुण

16

मेरा मानना ​​है कि यह सभी सांख्यिकीय रूप से टाइप की गई भाषाओं पर लागू होता है:

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

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

व्यावहारिक उपयोग में, आप एक अधिक सामान्य वर्ग पर काम करने वाले कोड लिख सकते हैं, लेकिन इसे एक उपवर्ग में डाल सकते हैं यदि आप जानते हैं कि यह क्या उपवर्ग है और इसे इस तरह से व्यवहार करने की आवश्यकता है। एक विशिष्ट उदाहरण Object.equals () से आगे निकल रहा है। मान लें कि हमारे पास कार के लिए एक वर्ग है:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}

मुझे यह शब्द बहुत पसंद है और मैं इसे और अधिक स्पष्ट करने के लिए आपकी पोस्ट को संपादित करूंगा
Charaf JRA

5

हम सभी देख सकते हैं कि आपके द्वारा प्रदान किया गया कोड रन टाइम पर काम नहीं करेगा। ऐसा इसलिए है क्योंकि हम जानते हैं कि अभिव्यक्ति है new A()कर सकते हैं कभी नहीं प्रकार का ऑब्जेक्ट हो B

लेकिन ऐसा नहीं है कि कंपाइलर इसे कैसे देखता है। जब तक संकलक जाँच कर रहा है कि क्या कलाकारों को अनुमति दी गई है, तब तक वह इसे देखता है:

variable_of_type_B = (B)expression_of_type_A;

और जैसा कि दूसरों ने प्रदर्शित किया है, उस तरह का कास्ट पूरी तरह से कानूनी है। सही पर अभिव्यक्ति बहुत अच्छी तरह से किसी वस्तु का मूल्यांकन कर सकती है B। संकलक देखता है कि Aऔर Bएक उप-प्रकार संबंध है, इसलिए कोड के "अभिव्यक्ति" दृश्य के साथ, कलाकार काम कर सकता है।

संकलक विशेष मामले पर विचार नहीं करता है जब यह जानता है कि वास्तव में क्या वस्तु प्रकार expression_of_type_Aहोगा। यह सिर्फ स्थैतिक प्रकार को देखता है Aऔर मानता है कि गतिशील प्रकार Aकिसी भी वंशज या का वंशज हो सकता है A, जिसमें शामिल है B


3

इस स्थिति में, जावा डाउनकास्टिंग की अनुमति क्यों देता है यदि इसे रनटाइम पर निष्पादित नहीं किया जा सकता है?

मेरा मानना ​​है कि ऐसा इसलिए है क्योंकि कंपाइलर के पास कंपाइल-टाइम में यह जानने का कोई तरीका नहीं है कि कास्ट सफल होगा या नहीं। आपके उदाहरण के लिए, यह देखना आसान है कि कलाकार विफल हो जाएगा, लेकिन ऐसे समय भी हैं जहां यह इतना स्पष्ट नहीं है।

उदाहरण के लिए, कल्पना करें कि बी, सी और डी सभी प्रकार ए का विस्तार करते हैं, और फिर एक विधि public A getSomeA()यादृच्छिक रूप से उत्पन्न संख्या के आधार पर या तो बी, सी या डी का एक उदाहरण देता है। कंपाइलर को यह पता नहीं चल सकता है कि कौन सा रन-टाइम टाइप इस विधि द्वारा वापस किया जाएगा, इसलिए यदि आप बाद में परिणाम डालते हैं B, तो यह जानने का कोई तरीका नहीं है कि क्या कलाकार सफल होगा (या विफल)। इसलिए संकलक को यह मान लेना होगा कि कलाकार सफल होंगे।


2

@ मूल पोस्टर - इनलाइन टिप्पणियां देखें।

public class demo 
{
    public static void main(String a[]) 
    {
        B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException 
        //- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

        //For downcast, what you need is a superclass ref containing a subclass object.
        A superClassRef = new B();//just for the sake of illustration
        B subClassRef = (B)superClassRef; // Valid downcast. 
    }
}

class A 
{
    public void draw() 
    {
        System.out.println("1");
    }

    public void draw1() 
    {
        System.out.println("2");
    }
}

class B extends A 
{
    public void draw() 
    {
        System.out.println("3");
    }

    public void draw2() 
    {
        System.out.println("4");
    }
}

2

डाउनकास्ट उस स्थिति में काम करता है जब हम एक अपस्टेड ऑब्जेक्ट के साथ काम कर रहे होते हैं। upcasting:

int intValue = 10;
Object objValue = (Object) intvalue;

तो अब इस objValueवैरिएबल हमेशा के लिए downcasted जा सकती है, intक्योंकि जिस वस्तु डाली था एक है Integer,

int oldIntValue = (Integer) objValue;
// can be done 

लेकिन क्योंकि objValueयह एक वस्तु है , इसलिए इसे कास्ट नहीं किया जा सकता Stringक्योंकि intइसे नहीं डाला जा सकता String


0

डाउनकास्टिंग निम्नलिखित कोड स्निपेट में बहुत उपयोगी है जिसका मैं हर समय उपयोग करता हूं। इस प्रकार यह साबित करना कि डाउनकास्टिंग उपयोगी है।

private static String printAll(LinkedList c)
{
    Object arr[]=c.toArray();
    String list_string="";
    for(int i=0;i<c.size();i++)
    {
        String mn=(String)arr[i];
        list_string+=(mn);
    }
    return list_string;
}

मैं स्ट्रिंग को लिंक्ड सूची में संग्रहीत करता हूं। जब मैं लिंक्ड सूची के तत्वों को पुनः प्राप्त करता हूं, तो ऑब्जेक्ट वापस कर दिए जाते हैं। तत्वों को स्ट्रिंग्स (या किसी अन्य क्लास ऑब्जेक्ट) के रूप में एक्सेस करने के लिए डाउनकास्टिंग से मुझे मदद मिलती है।

जावा हमें डाउनकास्ट कोड संकलित करने की अनुमति देता है, जो हमें विश्वास दिलाता है कि हम गलत काम कर रहे हैं। फिर भी अगर इंसान कोई गलती करता है तो उसे रनटाइम पर पकड़ा जाता है।


जावा में गैर-सामान्य संग्रह का उपयोग करना void*C ++ में पॉइंटर्स के बराबर है । यह मेरे लिए एक अच्छे विचार की तरह नहीं है।
जेजोर

0

नीचे दिए गए उदाहरण पर विचार करें

public class ClastingDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    AOne obj = new Bone();
    ((Bone) obj).method2();
}
}

class AOne {
public void method1() {
    System.out.println("this is superclass");
}
}


 class Bone extends AOne {

public void method2() {
    System.out.println("this is subclass");
}
}

यहां हम उपवर्ग अस्थि की वस्तु बनाते हैं और इसे सुपर क्लास एओएन संदर्भ को सौंपा है और अब सुपरक्लास संदर्भ उपखंड में विधि मेथड 2 के बारे में नहीं जानता है। संकलन समय के दौरान अस्थि। इसलिए हमें उपवर्ग संदर्भ के लिए सुपरक्लास के इस संदर्भ को नीचे करने की आवश्यकता है। परिणामी संदर्भ उपवर्ग अर्थात हड्डी में विधियों की उपस्थिति के बारे में जान सकता है


एक कुछ भ्रामक लग रहा है। कृपया अपने वर्ग के नाम को डॉग एंड एनिमल या किसी चीज़ में बदलने पर विचार करें
कार्तिक चुघ

0

जावा में डाउनकास्टिंग करने के लिए, और रन-टाइम अपवादों से बचने के लिए, निम्न कोड का संदर्भ लें:

if (animal instanceof Dog) {
  Dog dogObject = (Dog) animal;
}

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


0

वस्तुओं का डाउनकास्टिंग परिवर्तन संभव नहीं है। केवल

DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);

सकारात्मक है

class DownCasting0 {
    public int qwe() {
        System.out.println("DownCasting0");
        return -0;
    }
}

class DownCasting1 extends DownCasting0 {
    public int qwe1() {
        System.out.println("DownCasting1");
        return -1;
    }
}

class DownCasting2 extends DownCasting1 {
    public int qwe2() {
        System.out.println("DownCasting2");
        return -2;
    }
}

public class DownCasting {

    public static void main(String[] args) {

        try {
            DownCasting0 downCasting0 = new DownCasting0();
            DownCasting1 downCasting1 = new DownCasting1();
            DownCasting2 downCasting2 = new DownCasting2();

            DownCasting0 a1 = (DownCasting0) downCasting2;
            a1.qwe(); //good

            System.out.println(downCasting0 instanceof  DownCasting2);  //false
            System.out.println(downCasting1 instanceof  DownCasting2);  //false
            System.out.println(downCasting0 instanceof  DownCasting1);  //false

            DownCasting2 _downCasting1= (DownCasting2)downCasting1;     //good
            DownCasting1 __downCasting1 = (DownCasting1)_downCasting1;  //good
            DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException

            if(downCasting0 instanceof  DownCasting2){ //false
                DownCasting2 a2 = (DownCasting2) downCasting0;
                a2.qwe(); //error
            }

            byte b1 = 127;
            short b2 =32_767;
            int b3 = 2_147_483_647;
//          long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
            long b4 = 9_223_372_036_854_775_807L;
//          float _b5 = 3.4e+038; //double default
            float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
            double b6 = 1.7e+038;
            double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits

            long c1 = b3;
            int c2 = (int)b4;

            //int       4 bytes     Stores whole numbers from -2_147_483_648 to 2_147_483_647
            //float     4 bytes     Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
            float c3 = b3; //logic error
            double c4 = b4; //logic error


        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.