2010-11-02 18 views
78

मैं जावा Cloneable के बारे में समझाते हुए कुछ ट्यूटोरियल ढूंढ रहा था, लेकिन कोई अच्छा लिंक नहीं मिला, और स्टैक ओवरफ़्लो वैसे भी अधिक स्पष्ट विकल्प बन रहा है।जावा क्लोनेबल के बारे में

मैं निम्नलिखित जानना चाहूंगा:

  1. Cloneable मतलब है कि हम एक क्लोन या वस्तुओं की एक प्रति, द्वारा Cloneable इंटरफेस को लागू कर सकते हैं। क्या फायदे हैं और ऐसा करने के नुकसान क्या हैं?
  2. यदि ऑब्जेक्ट समग्र ऑब्जेक्ट है तो रिकर्सिव क्लोनिंग कैसे होती है?

धन्यवाद।

+2

क्या तुलना में फायदे और नुकसान? – Galactus

+0

मैंने पढ़ा कि क्लोनबल बनाम नहीं होने वाले वर्ग के लाभ का मतलब है। सुनिश्चित नहीं है कि इसका अर्थ कैसे और समझा जा सकता है: एस – allyourcode

उत्तर

129

सबसे पहले आपको Cloneable के बारे में पता होना चाहिए - इसका उपयोग न करें।

Cloneable के साथ क्लोनिंग को लागू करना बहुत मुश्किल है, और प्रयास इसके लायक नहीं है।

के बजाय है कि कुछ अन्य विकल्प, अपाचे-कॉमन्स SerializationUtils (गहरे क्लोन) या BeanUtils (उथले-क्लोन) की तरह उपयोग करते हैं, या बस एक कॉपी-निर्माता का उपयोग करें।

See here जोश ब्लोच के विचारों के लिए Cloneable के साथ क्लोनिंग के बारे में, जो दृष्टिकोण की कई कमियों को बताता है। (Joshua Bloch एक सूर्य कर्मचारी था, और कई जावा सुविधाओं के विकास के लिए नेतृत्व किया।)

+0

मैंने ब्लोच के शब्दों को जोड़ने (उन्हें उद्धृत करने के बजाय) – Bozho

+2

ध्यान दें कि ब्लॉक क्लोनेबल का उपयोग न करने का कहना है। वह नहीं कहता कि क्लोनिंग का उपयोग न करें (या कम से कम मुझे उम्मीद नहीं है)। क्लोनिंग को लागू करने के कई तरीके हैं जो सीरियलाइजेशन यूट्स या बीनयूटिल जैसे वर्गों की तुलना में कहीं अधिक कुशल हैं जो प्रतिबिंब का उपयोग करते हैं। उदाहरण के लिए नीचे मेरी पोस्ट देखें। – Charles

10
  1. क्लोनिंग वस्तुओं के निर्माण की एक अतिरिक्त भाषाई तरह से आह्वान - कंस्ट्रक्टर्स के बिना।
  2. क्लोनिंग के लिए आपको CloneNotSupportedException के साथ किसी भी तरह से इलाज करने की आवश्यकता है - या इसे इलाज के लिए क्लाइंट कोड परेशान करने की आवश्यकता है।
  3. लाभ छोटे हैं - आपको बस एक प्रतिलिपि बनाने वाले निर्माता को मैन्युअल रूप से लिखना नहीं है।

तो, क्लोनेबल को समझदारी से उपयोग करें। यह आपको सही सब कुछ करने के लिए आवेदन करने की आवश्यकता के मुकाबले पर्याप्त लाभ नहीं देता है।

+0

बोझो ने कहा, क्लोनेबल का उपयोग न करें। इसके बजाय, एक प्रति-निर्माता का उपयोग करें। http://www.javapractices.com/topic/TopicAction.do?Id=12 – Bane

+0

@ बेन, अगर आप क्लोन करने के लिए ऑब्जेक्ट के प्रकार को नहीं जानते हैं, तो आप कैसे जानेंगे कि किस वर्ग की कॉपी कन्स्ट्रक्टर का आह्वान करना है? –

+0

@Steve: मैं पालन नहीं करता हूं। यदि आप किसी ऑब्जेक्ट को क्लोन करने जा रहे हैं, तो मुझे लगता है कि आप पहले ही जानते हैं कि यह किस प्रकार है - आखिरकार, आपके पास ऑब्जेक्ट है कि आप क्लोनिंग पर योजना बना रहे हैं। और यदि ऐसी स्थिति है जहां आपकी ऑब्जेक्ट ने इसे अधिक सामान्य रूप से विशिष्ट प्रकार से खो दिया है, तो क्या आप इसे 'सरल' उदाहरण का उपयोग करके मूल्यांकन नहीं कर सकते ??? – Bane

4

ए) एक प्रतिलिपि निर्माता पर क्लोन के बहुत सारे फायदे नहीं हैं। शायद सबसे बड़ा एक ही गतिशील प्रकार की एक नई वस्तु बनाने की क्षमता है (माना जाता है कि घोषित प्रकार क्लोनबल है और इसमें सार्वजनिक क्लोन विधि है)।

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

बोझो सही है, क्लोन सही हो सकता है। एक प्रतिलिपि निर्माता/कारखाने ज्यादातर जरूरतों को पूरा करेगा।

34

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

क्या करता है, संरक्षित Object.clone() विधि है, जो कक्षाओं कि Cloneable को लागू नहीं करते के लिए एक CloneNotSupportedException फेंक देंगे, और वर्गों है कि के लिए एक सदस्य के लिहाज से उथले प्रतिलिपि प्रदर्शन के व्यवहार को बदलने के लिए है।

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

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

यह दृष्टिकोण किसी भी तर्क है कि अपने कंस्ट्रक्टर्स में हालांकि परिभाषित किया जा सकता है, जो संभावित रूप से समस्या हो सकता है नजरअंदाज।

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

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

अधिक जानकारी और Cloneable के संभावित नुकसान के लिए, मैं अत्यधिक पुस्तक प्रभावी जावा यहोशू बलोच द्वारा की सिफारिश

5

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

मान लीजिए मैं वर्गों ए, बी, और सी, जहां बी और सी ए से प्राप्त कर रहे हैं मैं एक इस तरह ग्रुप ए की वस्तुओं की सूची है है

ArrayList<A> list1; 

अब, उस सूची कर सकते हैं ए, बी, या सी प्रकार की वस्तुएं आप नहीं जानते कि वस्तुएं किस प्रकार हैं। तो, अगर आप इस तरह की सूची की प्रतिलिपि नहीं कर सकते हैं:

ArrayList<A> list2 = new ArrayList<A>(); 
for(A a : list1) { 
    list2.add(new A(a)); 
} 

तो ऑब्जेक्ट प्रकार बी या सी का वास्तव में है, तो आप सही प्रतिलिपि प्राप्त नहीं होंगे। और, क्या होगा अगर ए सार है? अब, कुछ लोगों ने यह सुझाव दिया है:

ArrayList<A> list2 = new ArrayList<A>(); 
for(A a : list1) { 
    if(a instanceof A) { 
     list2.add(new A(a)); 
    } else if(a instanceof B) { 
     list2.add(new B(a)); 
    } else if(a instanceof C) { 
     list2.add(new C(a)); 
    } 
} 

यह एक बहुत ही बुरा विचार है। क्या होगा यदि आप एक नया व्युत्पन्न प्रकार जोड़ते हैं? क्या होगा यदि बी या सी दूसरे पैकेज में हैं और आपके पास इस कक्षा में उनकी पहुंच नहीं है?

इस आप क्या करना चाहते हैं:

ArrayList<A> list2 = new ArrayList<A>(); 
for(A a : list1) { 
    list2.add(a.clone()); 
} 

बहुत से लोग यह संकेत दिया है कि क्यों क्लोन के बुनियादी जावा कार्यान्वयन समस्याग्रस्त है।

वर्ग एक में:

public A clone() { 
    return new A(this); 
} 

वर्ग बी में:

@Override 
public B clone() { 
    return new B(this); 
} 

वर्ग सी में:

@Override 
public C clone() { 
    return new C(this): 
} 

कार्यान्वयन के लिए मैं नहीं कर रहा हूँ लेकिन, यह आसानी से इस तरह से काबू पाने के है क्लोनेबल, बस एक ही फ़ंक्शन नाम का उपयोग करना। यदि आपको यह पसंद नहीं है, तो इसे और कुछ नाम दें।

+0

मैंने अलग टिप्पणी में आपकी टिप्पणी का जवाब देने के बाद इसे देखा; मैं देखता हूं कि अब आप कहां जा रहे हैं, हालांकि 2 चीजें: 1) ओपी ने विशेष रूप से क्लोनेबल (क्लोनिंग की सामान्य अवधारणा के बारे में नहीं) के बारे में पूछा, और 2) आप एक कॉपी-कन्स्ट्रक्टर के बीच अंतर करने की कोशिश में थोड़ा सा बाल बांट रहे हैं और क्लोनिंग की सामान्य अवधारणा। जो विचार आप यहां व्यक्त करते हैं वह मान्य है, लेकिन इसकी जड़ पर आप केवल एक प्रति-निर्माता का उपयोग कर रहे हैं। ;) – Bane

+0

हालांकि मैं यह कहना चाहता हूं कि मैं यहां आपके दृष्टिकोण से सहमत हूं, जिसमें उपयोगकर्ता को कॉपी-कन्स्ट्रक्टर को सीधे कॉल करने के लिए मजबूर करने के बजाय ए # copyMethod() शामिल है। – Bane

0

क्लोनेबल के नुकसान क्या हैं?

माना कि आप एक वस्तु डाटाबेस को संभालने के लिए है: यदि वस्तु जिसे आप कॉपी कर रहे composition.You इस मामले में संभव पक्ष प्रभाव नीचे के बारे में सोचना है क्योंकि क्लोन उथले कॉपी बन जाती है की जरूरत है

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

तो जब कोई originalObject का क्लोन बनाता है, तो ऑब्जेक्ट बनाया जा रहा है, कहें, cloneObject। यहां originalObject और cloneObjectConnection ऑब्जेक्ट के लिए एक ही संदर्भ रखें।

Let कहना originalObject बंद कर देता है Connection वस्तु है, इसलिए अब cloneObject काम नहीं करेगा क्योंकि connection वस्तु उन दोनों के बीच साझा किया गया था और यह actaually originalObject द्वारा बंद कर दिया गया था।

इसी तरह की समस्या तब हो सकती है जब आप कहें कि आप किसी ऑब्जेक्ट को क्लोन करना चाहते हैं जिसमें आईओएसट्रीम एक संपत्ति के रूप में है।

यदि वस्तु एक समग्र वस्तु है तो रिकर्सिव क्लोनिंग कैसे होती है?

क्लोनेबल उथले प्रतिलिपि करता है। मतलब यह है कि मूल वस्तु और क्लोन ऑब्जेक्ट का डेटा उसी संदर्भ/स्मृति को इंगित करेगा। गहरी प्रतिलिपि के मामले में, मूल वस्तु की स्मृति से डेटा क्लोन ऑब्जेक्ट की स्मृति में कॉपी किया गया है।

संबंधित मुद्दे