2011-02-01 12 views
96
public class Animal { 
    public void eat() {} 
} 

public class Dog extends Animal { 
    public void eat() {} 

    public void main(String[] args) { 
     Animal animal = new Animal(); 
     Dog dog = (Dog) animal; 
    } 
} 

उपवर्ग के लिए काम Dog dog = (Dog) animal; एक संकलन त्रुटि उत्पन्न नहीं करता है, लेकिन क्रम में यह एक ClassCastException उत्पन्न करता है। संकलक इस त्रुटि का पता क्यों नहीं लगा सकता?स्पष्ट कास्टिंग

Animal animal = new Dog(); 

आम तौर पर, downcasting एक अच्छा विचार नहीं है:

+41

आप संकलक को त्रुटि का पता लगाने के लिए कह रहे हैं। – Mauricio

उत्तर

222

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

चूंकि जानवर वास्तव में एक कुत्ता नहीं है (यह एक जानवर है, आप Animal animal = new Dog(); कर सकते हैं और यह एक कुत्ता होगा) वीएम रनटाइम पर अपवाद फेंकता है क्योंकि आपने उस ट्रस्ट का उल्लंघन किया है (आपने संकलक को सबकुछ बताया ठीक रहेगा और यह नहीं है!)

संकलक कुछ हद तक स्वीकार करने से थोड़ा अधिक चालाक है, अगर आप अलग-अलग उत्तराधिकारी पदानुक्रमों में ऑब्जेक्ट्स को डालने और डालने का प्रयास करते हैं (उदाहरण के लिए एक कुत्ते को एक कुत्ते को कास्ट करें) तो संकलक इसे फेंक देगा आप पर वापस क्योंकि यह जानता है कि संभवतः कभी काम नहीं कर सकता।

क्योंकि आप अनिवार्य रूप से सिर्फ शिकायत से संकलक रोक रहे हैं, हर बार जब आप डाली यह जाँच करने के लिए है कि आप एक ClassCastException का कारण नहीं बनेगा महत्वपूर्ण है एक अगर बयान (या उस प्रभाव के लिए कुछ।)

+0

धन्यवाद लेकिन आपको कुत्ते को पशु से विस्तार करने की आवश्यकता नहीं है, काम नहीं कर रहा है :) – delive

+14

मुझे प्यार है कि आपने इसे कितना नाटकीय बनाया है –

+1

@delive बेशक आप करते हैं, लेकिन अनुसार प्रश्न, 'कुत्ते' * * पशु 'से बढ़ाता है! – berry120

38

क्योंकि सैद्धांतिक रूप से Animal animal एक कुत्ता हो सकता है। आपको इससे बचना चाहिए। आप इसका इस्तेमाल करते हैं, तो आप बेहतर एक जांच में शामिल हैं:

if (animal instanceof Dog) { 
    Dog dog = (Dog) animal; 
} 
+0

लेकिन निम्न कोड संकलन त्रुटि उत्पन्न करता है कुत्ता कुत्ता = नया पशु(); (असंगत प्रकार)। लेकिन इस स्थिति में कंपाइलर पहचानता है कि पशु एक सुपर क्लास है और कुत्ता एक उप-वर्ग है। इसलिए असाइनमेंट गलत है। लेकिन जब हमने कुत्ते कुत्ते = (कुत्ते) जानवर को डाला; यह स्वीकार करता है। कृपया मुझे इस – saravanan

+3

हां के बारे में समझाएं, क्योंकि पशु सुपरक्लास है। हर जानवर एक कुत्ता नहीं है, है ना? आप कक्षाओं को केवल उनके प्रकार या उनके supertypes द्वारा संदर्भित कर सकते हैं। उनके उपप्रकार नहीं। – Bozho

+1

इसलिए संकलक केवल हमें कास्टिंग पर भरोसा करते हैं .. यह सही – saravanan

1

कोड एक संकलन त्रुटि उत्पन्न क्योंकि आपके उदाहरण प्रकार एक पशु है:

Animal animal=new Animal(); 

downcasting कई कारणों से जावा में अनुमति नहीं है । विवरण के लिए here देखें।

+5

कोई संकलन त्रुटि नहीं है, यही कारण है कि उनके प्रश्न –

30
में instanceof का उपयोग करके

आदेश ClassCastException इस तरह से बचने के लिए, यदि आपके पास में:

class A 
class B extends A 

आप बी में एक निर्माता है कि ए के इस तरह से हम क्या कर सकते हैं एक वस्तु लेता है परिभाषित कर सकते हैं "डाली" उदाहरण के लिए:

public B(A a) { 
    super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A 
    // If B class has more attributes, then you would initilize them here 
} 
17

Dog d = (Dog)Animal; //Compiles but fails at runtime

यहां आप संकलक से कह रहे हैं "मेरा विश्वास करो। मैं जानता हूँ कि d वास्तव में एक Dog वस्तु के लिए बात कर रहा है "हालांकि यह नहीं है। संकलक याद रखें हम पर विश्वास करने के लिए जब हम एक खिन्न करना पड़ता है।

संकलक केवल घोषित संदर्भ प्रकार के बारे में जानता है। JVM पर रनटाइम जानता है कि ऑब्जेक्ट वास्तव में क्या है।

तो जब रनटाइम पर JVM का पता लगा लेता है कि Dog d वास्तव में एक Animal और नहीं एक Dog वस्तु यह कहता है कि करने के लिए बात कर रहा है। हे ... आप कंपाइलर से झूठ बोला और एक बड़ी वसा ClassCastException फेंकता है।

तो यदि आप डाउनकास्टिंग कर रहे हैं तो आपको खराब होने से बचने के लिए instanceof परीक्षण का उपयोग करना चाहिए।

अब एक सवाल हमारे मन में आता। क्यों नरक कंपाइलर डाउनकास्ट की अनुमति दे रहा है जब अंत में यह java.lang.ClassCastException फेंकने जा रहा है?

जवाब यह है कि सभी संकलक, सत्यापित है कि दो प्रकार के एक ही विरासत पेड़ में हैं ऐसा कर सकते हैं पर जो कुछ कोड है खिन्न से पहले आ सकता है, तो संभव है कि animal प्रकार dog की है निर्भर करता है।

कंपाइलर को उन चीज़ों की अनुमति देनी चाहिए जो रनटाइम पर संभव हो सके।

निम्नलिखित कोड snipet पर विचार करें:

public static void main(String[] args) 
{ 
    Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog 
    Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :) 
    d.eat(); 

} 

private static Animal getMeAnAnimal() 
{ 
    Animal animal = new Dog(); 
    return animal; 
} 

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

String s = (String)d; // ERROR : cannot cast for Dog to String

downcasting के विपरीत, upcasting परोक्ष काम करता है, क्योंकि जब आप Upcast आप परोक्ष विधि की संख्या सीमित कर रहे हैं आप, आह्वान कर सकते हैं रूप downcasting के विपरीत है, जो इसका तात्पर्य है कि बाद में, आप एक और विशिष्ट विधि का आह्वान करना चाहेंगे।

Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast

ऊपर Upcast के दोनों किसी भी बिना किसी अपवाद के ठीक से काम करेंगे क्योंकि एक कुत्ता है-ए पशु, एक पशु क्या कर सकते हैं anithing, एक कुत्ता कर सकते हैं। लेकिन यह सच वीका-विपरीत नहीं है।

1

समझाया गया है, यह संभव नहीं है। यदि आप सबक्लास की विधि का उपयोग करना चाहते हैं, तो सुपरक्लस (खाली हो सकता है) में विधि जोड़ने की संभावना का मूल्यांकन करें और उप-वर्गों से कॉल करें जो आप चाहते हैं (subclass) polymorphism के लिए धन्यवाद। तो जब आप d.method() कॉल करते हैं तो कॉल कास्टिंग के साथ सफल हो जाएगा, लेकिन यदि ऑब्जेक्ट कुत्ते नहीं होगा, तो कोई समस्या नहीं होगी