2012-12-02 7 views
10

मैं एक सरणी की एक गहरी प्रतिलिपि सही ढंग से करने पर पढ़ रहा था, हालांकि मैं #clone() को कार्यान्वित करने के बारे में उलझन में था। यह java.lang.Object वर्ग का एक सदस्य है, और अभी तक अगर आप javadocs पढ़ें:क्लोन करने योग्य इंटरफ़ेस में #clone() क्यों नहीं है?

पहला, अगर इस वस्तु के वर्ग इंटरफ़ेस Cloneable को लागू नहीं करता है, तो एक CloneNotSupportedException फेंक दिया है।

तो पहले स्थान पर clone विधि को परिभाषित क्यों करें? निश्चित रूप से यदि कोई इंटरफ़ेस मौजूद होने पर केवल एक विधि का उपयोग किया जा सकता है, तो आप विधि को इंटरफ़ेस में डाल देंगे। Cloneable इंटरफ़ेस स्वयं खाली है; यह जावा द्वारा उपयोग किया जाने वाला एक मार्कर इंटरफ़ेस है यह सुनिश्चित करने के लिए कि clone विधि का उपयोग कानूनी है।

यह ऐसा तरीका भी प्रकार सुरक्षा सुनिश्चित करने के जेनरिक का उपयोग करने के क्षमता को निकालता है:

class Foo implements Cloneable { // Valid. 
    @Override 
    public Object clone() throws CloneNotSupportedException { 
     // ... 
    } 
} 

class TypeSafeFoo implements Cloneable<TypeSafeFoo> { // Not valid. 
    @Override 
    public TypeSafeFoo clone() throws CloneNotSupportedException { 
     // ... 
    } 
} 

जावा इसे इस तरह क्यों किया? मुझे यकीन है कि उनके पास वैध कारण हैं, लेकिन मुझे इसका पता लगाना प्रतीत नहीं होता है।

+3

असल में यह एक डिजाइन दोष के रूप में यहोशू बलोच –

+0

यह क्लोनिंग टूटी माना जाता है कई कारणों में से एक है द्वारा कहा था: आप बस एक वस्तु जो इस util द्वारा Cloneable लागू करता क्लोन कर सकते हैं। –

उत्तर

14

जावा में क्लोनिंग अनुबंध यह निर्देश देता है कि प्रत्येक clone कार्यान्वयन को पहले super.clone() से क्लोन उदाहरण प्राप्त करना होगा। यह एक श्रृंखला बनाता है जो हमेशा कॉल के साथ Object.clone पर समाप्त होता है, और उस विधि में "जादुई" मूल-स्तर कोड होता है जो अंतर्निहित कच्चे struct की बाइनरी प्रति बनाता है जो जावा ऑब्जेक्ट का प्रतिनिधित्व करता है। यदि यह तंत्र मौजूद नहीं था, clone पॉलिमॉर्फिक होने में असफल होगा: Object.clone विधि उस वर्ग का एक उदाहरण उत्पन्न करती है जिसे इसे कहा जाता है; इसे देशी कोड के बिना पुन: उत्पन्न नहीं किया जा सकता है।

यही कारण है कि Object.clone विधि से बचा नहीं जा सका। Cloneable में clone विधि शामिल है, लेकिन यह throws खंड के संबंध में समस्याएं पैदा करेगा। जिस तरह से यह खड़ा है, आप घोषित अपवादों के साथ clone घोषित करने के लिए स्वतंत्र हैं, या मनमाने ढंग से अपवाद घोषित करने के लिए स्वतंत्र हैं। यदि इंटरफ़ेस में विधि पहले ही घोषित की गई थी तो यह लचीलापन संभव नहीं होगा।

ध्यान रखें कि जेनरिक क्लोनिंग के लिए बहुत कम उपयोग करेंगे: protected T clone()Object में: T कहां से आएगा? क्या हमें Object<T> की आवश्यकता होगी और जावा ब्रह्मांड में प्रत्येक और प्रत्येक वर्ग को पैरामीटरकृत करने के लिए मजबूर होना चाहिए, और यह सब सिर्फ अर्ध-बहिष्कृत तंत्र को थोड़ा बेहतर काम करने के लिए?मन में भी रखें कि यह कोड पूरी तरह से कानूनी है:

public class TheMightyOne implements Cloneable { 
    @Override public TheMightyOne clone() { 
    return (TheMightyOne) super.clone(); 
    } 
} 

आप इसे कॉल कर सकते हैं:

TheMightyOne one = new TheMightyOne(); 
TheMightyOne two = one.clone(); // do downcasts needed 
+0

जादू क्लोन विधि स्थिर बनाकर इनमें से अधिकतर से बचा नहीं जा सका? ऑब्जेक्ट.क्लोन (क्लोनेबल आइटम) '। फिर 'क्लोनेबल' को लागू करने वाली कोई भी चीज़ 'ऑब्जेक्ट' क्लोन' पर देगी। यह जेनरिक के साथ भी आसानी से काम कर सकता था। –

4

क्लोन और मूल फ़ील्ड प्रतिलिपि बनाने से निपटने के लिए, क्लोन को विधि कार्यान्वयन का उत्तराधिकारी होना आवश्यक है। एक क्लोनेबल क्लास पदानुक्रम में कहीं भी दिखाई दे सकती है, और इसके प्राथमिक नौकरी करने के लिए एक विशिष्ट सुपरक्लास का विस्तार करने की आवश्यकता हो सकती है। एकमात्र सुपरक्लास जिसमें से सभी संभावित क्लोनेबल कक्षाएं कार्यान्वयन का उत्तराधिकारी हो सकती हैं वस्तु है।

क्लोनिंग जेनेरिक से पहले लंबे समय से परिभाषित किया गया था।

0

clone() विधि अनावश्यक है, हर वस्तु Object.clone विधि आह्वान सकता द्वारा प्रतिबिंबित करती हैं, इसलिए एक वस्तु क्लोन किया जा सकता है इस पर निर्भर करता है कि Cloneable इंटरफ़ेस को कार्यान्वित करना है या नहीं। यह एक सुरक्षा कारण के लिए है।

@SuppressWarnings("unchecked") 
public static <T extends Cloneable> T clone(Cloneable obj) { 
    T rtn = null; 
    try { 
     Method method = Object.class.getDeclaredMethod("clone"); 
     method.setAccessible(true); 
     rtn = (T) method.invoke(obj); 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
    return rtn; 
} 
संबंधित मुद्दे