2010-05-23 5 views
11

प्रभावी जावा में, लेखक कहा गया है कि: एक वर्ग Cloneable लागू करताऑब्जेक्ट.क्लोन() द्वारा किया गया यह फ़ील्ड-बाय-फील्ड कॉपी क्या है?

हैं, तो वस्तु का क्लोन विधि वस्तु का एक क्षेत्र द्वारा क्षेत्र प्रतिलिपि रिटर्न; अन्यथा यह CloneNotSupportedException फेंकता है।

मैं क्या जानना चाहता हूं कि वह क्षेत्र-दर-क्षेत्र प्रतिलिपि के साथ क्या मतलब है। क्या इसका मतलब यह है कि यदि कक्षा में एक्स बाइट्स मेमोरी है, तो यह सिर्फ उस स्मृति के टुकड़े की प्रतिलिपि बनायेगा? यदि हां, तो क्या मैं मान सकता हूं कि मूल वर्ग के सभी मूल्य प्रकारों को नई वस्तु में कॉपी किया जाएगा? क्या Object.clone() करता Point वर्ग के क्षेत्र प्रतिलिपि द्वारा एक क्षेत्र है

class Point implements Cloneable{ 
    private int x; 
    private int y; 

    @Override 
    public Point clone() { 
     return (Point)super.clone(); 
    } 
} 

हैं, मैं कहेंगे कि मैं स्पष्ट रूप से क्षेत्रों x और y कॉपी करने के लिए, जा रहा है कि ऊपर दिखाए गए कोड की तुलना में अधिक हो जाएगा की जरूरत नहीं होगी Point कक्षा का क्लोन बनाने के लिए पर्याप्त है। यही है, कोड का निम्नलिखित बिट अनावश्यक है:

@Override 
public Point clone() { 
    Point newObj = (Point)super.clone(); 
    newObj.x = this.x; //redundant 
    newObj.y = this.y; //redundant 
} 

क्या मैं सही हूँ?

मुझे पता है कि क्लोन ऑब्जेक्ट के संदर्भ स्वचालित रूप से उस बिंदु पर इंगित करेंगे जहां मूल ऑब्जेक्ट के संदर्भों की ओर इशारा किया गया है, मुझे यकीन नहीं है कि विशेष रूप से मूल्य प्रकारों के साथ क्या होता है। अगर कोई स्पष्ट रूप से बता सकता है कि Object.clone() का एल्गोरिदम विनिर्देशन (आसान भाषा में) है जो बहुत अच्छा होगा।

उत्तर

5

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

class Line implements Cloneable { 

    private Point start; 
    private Point end; 

    public Line() { 
     //Careful: This will not happen for the cloned object 
     SomeGlobalRegistry.register(this); 
    } 

    @Override 
    public Line clone() { 
     //calling super.clone is going to create a shallow copy. 
     //If we want a deep copy, we must clone or instantiate 
     //the fields ourselves 
     Line line = (Line)super.clone(); 
     //assuming Point is cloneable. Otherwise we will 
     //have to instantiate and populate it's fields manually 
     line.start = this.start.clone(); 
     line.end = this.end.clone; 
     return line; 
    } 
} 

इसके अलावा क्लोनिंग के बारे में एक और महत्वपूर्ण बात यह है है, क्लोन वस्तु के निर्माता कभी नहीं शुरू हो जाती है (केवल क्षेत्रों कॉपी कर रहे हैं)। इसलिए यदि निर्माता बाहरी ऑब्जेक्ट को प्रारंभ करता है, या इस रजिस्ट्री को कुछ रजिस्ट्री के साथ पंजीकृत करता है, तो यह क्लोन ऑब्जेक्ट के लिए नहीं होगा।

मैं व्यक्तिगत रूप से जावा के क्लोनिंग का उपयोग नहीं करना पसंद करता हूं। इसके बजाय मैं आमतौर पर अपनी खुद की "नकल" विधियों का निर्माण करता हूं।

+0

आप जावा के क्लोनिंग का उपयोग क्यों नहीं करेंगे और अपनी खुद की विधि लिखेंगे? कोई विशिष्ट कारण? – zengr

+1

प्रभावी जावा पढ़ें। ऐसे बहुत से हैं। –

+0

http://www.javapractices.com/topic/TopicAction.do?Id=71 –

4

इसका मतलब है एक उथली प्रतिलिपि - फ़ील्ड की प्रतिलिपि बनाई जाती है, लेकिन यदि आपके पास कोई संदर्भ है, तो इन बिंदुओं की प्रतिलिपि नहीं बनाई गई है - आपके पास एक ही वस्तु के दो संदर्भ होंगे, एक पुरानी वस्तु में से एक और एक में नया, क्लोन ऑब्जेक्ट। हालांकि, उन क्षेत्रों के लिए जिनके पास आदिम प्रकार हैं, फ़ील्ड डेटा ही है, इसलिए उन्हें कॉपी किए बिना कॉपी किया जाता है।

+0

सही, हालांकि 'क्लोन' विधि को 'super.clone()' के रूप में लागू नहीं किया गया है, लेकिन यह * अनुबंध पर लागू नहीं हो सकता है। –

+0

आह हाँ, यह निश्चित रूप से सच है। मैंने देखा कि उदाहरण में कि वह क्लोनेबल को बढ़ाता है, जो गलत लगता है - आप इसे कार्यान्वित करेंगे और फिर क्लोनेबल विधि को ओवरराइड करेंगे (शायद क्लोनेबल को विस्तारित करना यह जावा 1 में कैसे काम करता है?)। मुझे लगता है कि इसे लागू करने का कहना है कि "अरे, मुझे यह विशेष क्लोनेबल प्रकृति मिल गई है, मैं ठीक से क्लोन कर रहा हूं और अपने क्लोन विधि में मैन्युअल गहरी प्रतिलिपि करता हूं"। हालांकि, जब तक आप ऑब्जेक्ट से क्लोन() को ओवरराइड नहीं करते हैं, जैसा कि आप कहते हैं, एक उथली प्रतिलिपि करता है। –

3
newObj.x = this.x; //redundant 
newObj.y = this.y; //redundant 

यह सही है - ये अनावश्यक हैं, क्योंकि वे ऑब्जेक्ट के क्लोन() विधि द्वारा पहले ही कॉपी हो चुके हैं।

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

class A implements Cloneable { 
    Object someObject; 
} 

A a = new A(); 
a.someObject = new Object(); 

A cloneA = (A)a.clone(); 
assert a.someObject==cloneA.someObject; 
1

डिफ़ॉल्ट क्लोन मूल्यों की उथली प्रतिलिपि करता है। आदिम मूल्यों के लिए, यह पर्याप्त है और कोई अतिरिक्त काम की आवश्यकता नहीं है।

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

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