2011-09-28 15 views
16

के साथ जावा ऑब्जेक्ट को क्लोन करने के लिए कैसे मैं क्लोनिंग कस्टम ऑब्जेक्ट की तंत्र को समझ नहीं पा रहा हूं। उदाहरण के लिए:क्लोन() विधि

public class Main{ 

    public static void main(String [] args) { 

     Person person = new Person(); 
     person.setFname("Bill"); 
     person.setLname("Hook"); 

     Person cloned = (Person)person.clone(); 
     System.out.println(cloned.getFname() + " " + cloned.getLname()); 
    } 
} 

class Person implements Cloneable{ 

    private String fname; 
    private String lname; 

    public Object clone() { 

     Person person = new Person(); 
     person.setFname(this.fname); 
     person.setLname(this.lname); 
     return person; 
    } 

    public void setFname(String fname) { 
     this.fname = fname; 
    } 

    public void setLname(String lname){ 
     this.lname = lname; 
    } 

    public String getFname(){ 
     return fname; 
    } 

    public String getLname() { 
     return lname; 
    } 
} 

यह उदाहरण पुस्तकें लिखने के रूप में क्लोनिंग का सही तरीका दिखाता है। लेकिन मैं वर्ग नाम परिभाषा में क्लोनबल लागू कर सकता हूं और मुझे एक ही परिणाम मिलते हैं।

तो मुझे क्लोनेबल के प्रस्ताव को समझ में नहीं आता है और क्यों क्लास ऑब्जेक्ट में क्लोन() विधि परिभाषित की गई है?

+0

जावाडोक देखें: http://download.oracle.com/javase/6/docs/api/java/lang/Cloneable.html –

+0

http://stackoverflow.com/questions/2156120/java-recommended-solution-for-deep-cloning-copying-an-instance/2156367#2156367 – Bozho

+0

http: // stackoverflow।com/प्रश्न/3180599/Javas क्लोन-विधि-जनरेटर के लिए ग्रहण-गैलीलियो/3180729 # 3180729 – Bozho

उत्तर

8

कक्षा Object में clone() कन्स्ट्रक्टर जैसी विधियों को कॉल करने की बजाय स्मृति की उथली प्रतिलिपि करता है। clone() को किसी भी ऑब्जेक्ट पर कॉल करने के लिए जो clone() को लागू नहीं करता है, आपको Clonable इंटरफ़ेस को लागू करने की आवश्यकता है।

यदि आप clone() विधि को ओवरराइड करते हैं तो आपको उस इंटरफ़ेस को लागू करने की आवश्यकता नहीं है।

बस के रूप में JavaDoc कहते हैं, यह एक अपवाद में परिणाम होगा:

class A { 
    private StringBuilder sb; //just some arbitrary member 
} 

... 

new A().clone(); //this will result in an exception, since A does neither implement Clonable nor override clone() 

तो A उदाहरण में Clonableclone() (Object संस्करण) बुला लागू करेगा एक नया A उदाहरण संदर्भ में परिणाम होगा क्लोनबिल्डर में स्ट्रिंगबिल्डर, यानि sb में परिवर्तन के परिणामस्वरूप sb में A इंस्टेंस में परिवर्तन होगा।

इसका मतलब उथले प्रतिलिपि के साथ है और यही कारण है कि clone() को ओवरराइड करना आम तौर पर बेहतर होता है।

संपादित करें: बस एक sidenote के रूप में, वापसी प्रकार सहप्रसरण का उपयोग कर की वजह से आपके अधिरोहित clone() अधिक स्पष्ट:

public Person clone() { 
    ... 
} 
+0

थॉमस, अगर मैं एक में Cloneable को लागू नहीं करते और क्लोन ओवरराइड नहीं करें() मैं त्रुटि संकलन प्राप्त करते हैं, क्योंकि क्लोन() सुरक्षित है –

+0

@Dmytro हाँ, उदाहरण के बस बिंदु को वर्णन करना था। आप 'क्लोन()' को कॉल कर सकते हैं, भले ही इसे प्रतिबिंब का उपयोग करके सुरक्षित किया गया हो, या आप अपने ओवरराइड संस्करण में 'super.clone()' को कॉल कर सकते हैं - दोनों मामलों में आपको 'क्लोनबल' इंटरफ़ेस गुम होने पर अपवाद प्राप्त होगा। – Thomas

0

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

0

ऑब्जेक्ट को clone() विधि में स्पष्ट रूप से यहां बनाने की आवश्यकता नहीं है। बस super.clone() पर कॉल करके इस ऑब्जेक्ट की प्रतिलिपि बनाई जाएगी। यह उथले क्लोन प्रदर्शन करेगा।

8

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

class Person implements Cloneable { 
    // ... 
    @Override 
    public Object clone() throws CloneNotSupportedException { 
     return super.clone(); 
    } 
} 

या

class Person implements Cloneable { 
    // ... 
    @Override 
    public Object clone() { 
     try { 
      return super.clone(); 
     } 
     catch (CloneNotSupportedException e) { 
      throw new Error("Something impossible just happened"); 
     } 
    } 
} 

तब भी, जब व्यक्ति वर्ग, subclassed है, जबकि अपने क्लोन कार्यान्वयन हमेशा व्यक्ति का एक उदाहरण पैदा करेगा (और के लिए कर्मचारी की नहीं एक उदाहरण काम करेंगे एक कर्मचारी, उदाहरण के लिए)।

0

यदि आप क्लोन करने योग्य इंटरफ़ेस घोषित नहीं करते हैं तो आपको क्लोन विधि को कॉल करने पर क्लोन नॉटस्पोर्टपोर्ट प्राप्त करना चाहिए। अगर आप घोषणा करते हैं और फिर क्लोन विधि को कॉल करते हैं तो यह उथली प्रतिलिपि बना देगा।

12

क्लोन विधि एक गहरी प्रति बनाने के लिए है। सुनिश्चित करें कि आप गहरी और उथली प्रतियों के बीच का अंतर समझते हैं। आपके मामले में एक कॉपी कन्स्ट्रक्टर वह पैटर्न हो सकता है जो आप चाहते हैं। कुछ मामलों में आप इस पैटर्न का उपयोग नहीं कर सकते हैं, उदाहरण के लिए, क्योंकि आप क्लास एक्स को उप-वर्गीकृत कर रहे हैं और आपके पास एक्स के कन्स्ट्रक्टर तक पहुंच नहीं है जिसे आपको चाहिए। सामान्य तौर पर

class Y extends X implements Cloneable { 

    private SomeType field; // a field that needs copying in order to get a deep copy of a Y object 

    ... 

    @Override 
    public Y clone() { 
     final Y clone; 
     try { 
      clone = (Y) super.clone(); 
     } 
     catch (CloneNotSupportedException ex) { 
      throw new RuntimeException("superclass messed up", ex); 
     } 
     clone.field = this.field.clone(); 
     return clone; 
    } 

} 

जब अपने क्लोन विधि अधिभावी:: एक्स सही ढंग से अपने क्लोन विधि ओवरराइड करता है तो (यदि आवश्यक हो) तो आप निम्नलिखित तरीके से एक प्रतिलिपि बना सकता है

  • वापसी प्रकार अधिक विशिष्ट
  • बनाओ
  • प्रारंभ super.clone()
  • बुला शामिल न करें साथ खंड फेंकता है जब आप जानते हैं clone() भी किसी उपवर्ग के लिए काम करेंगे (क्लोन पैटर्न की कमजोरी; वर्ग यदि संभव हो तो अंतिम बनाना)
  • +०१२३५१६४१०
  • अकेले अपरिवर्तनीय और आदिम क्षेत्रों को छोड़ दें, लेकिन (, क्लोन पैटर्न की एक और कमजोरी के बाद से इन क्षेत्रों अंतिम नहीं बनाया जा सकता) मैन्युअल super.clone() करने के लिए कॉल के बाद परिवर्तनशील वस्तु क्षेत्रों क्लोन

Object की clone() विधि (जो आखिरकार जब कॉल किया जाएगा तो सभी सुपरक्लास अनुबंध का पालन करेंगे) एक उथली प्रतिलिपि बनाता है और नई वस्तु के सही रनटाइम प्रकार का ख्याल रखता है। ध्यान दें कि पूरी प्रक्रिया में कोई कन्स्ट्रक्टर कैसे नहीं कहा जाता है।

यदि आप उदाहरणों पर clone() पर कॉल करने में सक्षम होना चाहते हैं, तो Cloneable इंटरफ़ेस को लागू करें और विधि को सार्वजनिक बनाएं। यदि आप इसे उदाहरणों पर कॉल नहीं करना चाहते हैं, लेकिन आप यह सुनिश्चित करना चाहते हैं कि सबक्लास अपने super.clone() पर कॉल कर सकें और उन्हें क्या चाहिए, तो Cloneable लागू न करें और विधि protected रखें यदि आपका सुपरक्लास नहीं है इसे पहले से ही घोषित कर दिया।

क्लोन पैटर्न मुश्किल है और इसमें बहुत सी समस्याएं हैं। सुनिश्चित करें कि आपको वही चाहिए जो आपको चाहिए। कॉपी कन्स्ट्रक्टर, या एक स्थिर फैक्ट्री विधि पर विचार करें।

0

आपके उदाहरण में आप वास्तविक क्लोनिंग नहीं कर रहे हैं। आप ऑब्जेक्ट क्लास के क्लोन() विधि को ओवरराइड कर चुके हैं और अपना स्वयं का कार्यान्वयन दिया है। लेकिन आपके क्लोन विधि में आप एक नई व्यक्ति वस्तु बना रहे हैं। और इसे वापस कर रहा है। इसलिए इस मामले में वास्तविक वस्तु को क्लोन नहीं किया गया है।

तो अपने क्लोन विधि होना चाहिए की तरह:

public Object clone() { 
     return super.clone(); 
    } 

तो यहाँ क्लोन सुपर क्लास विधि द्वारा नियंत्रित किया जाएगा।

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