2009-06-27 19 views
6

मैंने इस क्लोन विधि को लिखा है जब कर्मचारी वर्ग के माता-पिता अमूर्त हैं और मूल वर्ग में क्लोन() विधि सारणी है। मैं प्रत्येक को कॉपी करने के बजाय इस कोड के साथ कर्मचारी के ऑब्जेक्ट के आदिम डेटा प्रकार की प्रतिलिपि बनाना चाहता था आदिम डेटा प्रकार अलग-अलग, लेकिन इस कोड में उस लाइन के साथ समस्या है जिसे मैं क्लोन() विधि कहता हूं। (यह कोड कर्मचारी वर्ग में है)इस क्लोन() के साथ क्या गलत है?

public Object clone() { 
    Object obj = new Object(); 
    Object object = obj.clone(); //Emphasis here 
    return object; 

} 

त्रुटि यह है कि प्रकार ऑब्जेक्ट से विधि क्लोन() दिखाई नहीं दे रहा है।

लेकिन मेरा कर्मचारी वर्ग कक्षा पदानुक्रम में है जो ऑब्जेक्ट क्लास में संरक्षित क्लोन() विधि तक पहुंच सकता है।

यह मेरा सरल कर्मचारी वर्ग है:

public class Employee extends Person implements Cloneable { 
private int ID; 

public Employee() { 
    ID = 0; 
} 

public void setID(int ID) { 
    this.ID = ID; 
} 

public int getID() { 
    return ID; 
} 

public Object clone1() throws CloneNotSupportedException { 
    try { 
     Object obj = new Object(); 

     Object object = obj.clone(); 
     return object; 
    } catch (CloneNotSupportedException ex) { 
     return null; 
    } 
} 
+0

+1 इसे यहां देखें। क्योंकि जैसा कि मैं समझता हूं कि यह पता है कि स्थिति वास्तव में एक साधारण क्लोन() मामला नहीं है, वास्तव में थोड़ा मुश्किल है। – akarnokd

उत्तर

2

आप अपनी वस्तु पर Cloneable इंटरफ़ेस को लागू किया था?

हालांकि, बहुत कम मामले हैं जो मैं ऑब्जेक्ट की प्रतिलिपि बनाने के लिए क्लोन का उपयोग करता हूं। ऐसा एक सुरक्षित उदाहरण array.clone() है। मैं बजाय कॉपी-कन्स्ट्रक्टर मुहावरे का उपयोग या मैन्युअल रूप से प्रतिलिपि/मूल्यों को असाइन करना चाहता हूं।

पृष्ठभूमि समस्या के बारे में Effective Java (द्वितीय संस्करण) में आइटम # 11 है। क्लोनेबल इंटरफ़ेस एक विशेष प्रकार का इंटरफ़ेस है क्योंकि यह क्लोनिंग के संबंध में Object वर्ग के व्यवहार को संशोधित करता है। असल में यह जावा में कक्षा इंटरफ़ेस सक्षम करने वाली सुविधा है।

संपादित करें: आपके उदाहरण के आधार पर आपको क्लोन नॉटस्प्पोर्टेड एक्सेप्शन के एक सामान्य मामले में क्लोन() कॉल को लपेटने की आवश्यकता हो सकती है।

EDIT2: आप public संदर्भ में क्लोन() ओवरराइड था: मेरा उत्तर

Edit3 पुनः निर्मित? नमूने में आप आप एक वस्तु है, जो java.lang पैकेज में है क्लोन करने के लिए कोशिश दे दी है - शायद ही पैकेज अपने कोड में है

Edit4:। मुझे लगता है कि इस सवाल का जवाब अन्य पदों में पहले से ही है, बस चाहता था अंतर्निहित मुद्दे पर प्रतिबिंबित करने के लिए।

Edit5: इस प्रयास करें:

public Object clone1() throws CloneNotSupportedException {   
    return super.clone();   
} 

Edit6 तो उदाहरण के लिए और कार्यान्वयन में अपने विधि public abstract Object copy() नाम, super.clone का उपयोग करें() - भ्रम से बचने के।

Edit7 मैं कुछ ग्रहण लगा था और निम्नलिखित समाधान के साथ बाहर आया था:

public class Cloner { 
    public static abstract class Person { 
     protected abstract Object clone1() throws CloneNotSupportedException; 
     public Object copy() throws CloneNotSupportedException { 
      return clone1(); 
     } 
    } 
    public static class Employee extends Person implements Cloneable { 
     @Override 
     protected Object clone1() throws CloneNotSupportedException { 
      return super.clone(); 
     } 

    } 
    public static void main(String[] args) throws Exception { 
     new Employee().copy(); 
    } 
} 

लेकिन मूल रूप से यह क्लोन से कुछ और करने के लिए अपने सार विधि का नाम बदलने के रूप में ही अवधारणा() है।

संपादित 8: मेरा नमूना तय किया गया, अब यह अपवाद के बिना काम करता है। पद से http://en.wikipedia.org/wiki/Clone_(Java_method)

एक अंश::

(लेकिन वास्तविक क्रेडिट Gábor Hargitai super.clone() के लिए को जाता है)

+0

हां मैंने क्लोनेबल इंटरफ़ेस लागू किया है। – Johanna

+0

मैंने इसे पकड़ने की कोशिश में रखा है लेकिन यह अभी भी वह त्रुटि है। – Johanna

+0

मैं super.clone() का उपयोग नहीं कर सकता हूं यहां सुपर व्यक्ति है और व्यक्ति का एक सार क्लोन है() !!! मैं super.clone() ???? – Johanna

0

आप उचित इंटरफ़ेस कार्यान्वित है? यह उतना आसान हो सकता है, हालांकि आप इसके लिए पहले से ही जिम्मेदार हो चुके हैं।

अधिक जानकारी के लिए यहाँ देखें: http://java.sun.com/javase/6/docs/api/java/lang/Object.html#clone()

+0

@dxmio: हाँ मैंने क्लोनेबल इंटरफेस को कार्यान्वित किया है। लेकिन यह भी त्रुटि है, और मुझे नहीं पता क्यों ??: (( – Johanna

0

मैं जावा साथ बहुत परिचित नहीं हूँ, लेकिन यह मदद मिल सकती है

Another disadvantage is that one often cannot access the clone() method on an abstract type. Most interfaces and abstract classes in Java do not specify a public clone() method. As a result, often the only way to use the clone() method is if you know the actual class of an object; which is contrary to the abstraction principle of using the most generic type possible. For example, if one has a List reference in Java, one cannot invoke clone() on that reference because List specifies no public clone() method. Actual implementations of List like ArrayList and LinkedList all generally have clone() methods themselves, but it is inconvenient and bad abstraction to carry around the actual class type of an object.

6

जावा क्लोनिंग तंत्र कुछ हद तक अजीब है। खुद को क्लोन करने में सक्षम होने के लिए कक्षा को दो चीजें करना चाहिए। सबसे पहले इसे क्लोनबल लागू करना होगा। दूसरा यह क्लोन() को ओवरराइड करना होगा और इसे सार्वजनिक बनाना होगा।

आपके उदाहरण में, आप क्लोन() को ओवरराइड करते हैं लेकिन आप कर्मचारी वर्ग पर क्लोन() नहीं आ रहे हैं बल्कि ऑब्जेक्ट.क्लास() पर क्लोन() केवल संरक्षित है।

+0

मुझे आपका जवाब नहीं मिला.तुम्हारे जवाब के लाइन 3 और 4 के साथ आपका क्या मतलब है ?? – Johanna

+0

यह लड़का सही है, ऑब्जेक्ट में क्लोन विधि नहीं है, केवल आईसीएलनेबल सामान करता है। मैं कहूंगा कि आपको आईसीएलनेबल में ओबीजे डालने की जरूरत है, फिर क्लोन कॉल करें लेकिन आप 'नए ऑब्जेक्ट' के साथ ओबीजे का निर्माण कर रहे हैं, ताकि वास्तव में क्लोन() न हो। आपको वास्तव में क्या लगता है कि आपका कोड करना चाहिए? – Blindy

+0

मुझे लगता है कि आईसीएलओबल योग्य सी # है? लेकिन अभी भी अपने बजाय क्लोनिंग ऑब्जेक्ट पर अच्छा बिंदु। – akarnokd

2

आप बस

return super.clone(); 
अपने क्लोन विधि में

लिखने और Clonable इंटरफ़ेस को लागू करना चाहिए।

+0

+1, जोहाना की टिप्पणी इटली पर – akarnokd

+0

पर आधारित है, इसलिए मैं नहीं कर सकता क्योंकि सुपर क्लास उदाहरण के लिए व्यक्ति है जिसमें अमूर्त क्लोन() विधि है। – Johanna

+0

यह कोई समस्या नहीं है, क्योंकि वास्तविक क्लोनिंग ऑब्जेक्ट क्लास द्वारा किया जाता है - आपको केवल क्लोनेबल को लागू करने की आवश्यकता होती है, जब तक कि आप व्यक्ति वर्ग पर एक सार क्लोन() विधि नहीं बनाते। – akarnokd

4

प्रभावी जावा के मिस्टर बलोच कुछ दिलचस्प शब्द clone के उपयोग पर क्या कहना है।

http://www.artima.com/intv/bloch13.html

आम तौर पर वर्तमान सोच के रूप में यह त्रुटियों की संभावना है और बहुत गलत समझा, प्रतिलिपि निर्माता को लागू करने के लिए एक वैकल्पिक रणनीति या गहरी नकल का एक जानवर बल दृष्टिकोण वस्तु क्रमबद्धता का उपयोग कर उपयोग कर रहा है क्लोन के उपयोग से बचने के लिए है।

+0

+1 केवल एक पुस्तक संदर्भ के बजाय एक पठनीय लेख प्रदान करना। – akarnokd

-2
आदेश में एक ठीक से cloneable वस्तु पाने के लिए

मूल रूप से एक सार्वजनिक क्लोन है करने के लिए पर्याप्त() विधि उस वर्ग में लागू है।

Cloneable इंटरफ़ेस वी एम को संकेत देना है कि यह क्षेत्र प्रतिलिपि द्वारा एक क्षेत्र के रूप में डिफ़ॉल्ट संरक्षित क्लोन() विधि को लागू करने के लिए प्रयोग किया जाता सुरक्षित है एक इंटरफेस है।

ताकि ठीक से एक वर्ग के लिए क्लोन विधि आप इस तरह एक सार्वजनिक विधि क्लोन घोषित करना चाहिए लागू करने के लिए()।

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

एक अच्छा काम कर implementationk एक नई वस्तु बनाने जाएगा और ठीक से व्यापार तर्क reaquires जैसे क्षेत्रों में निर्दिष्ट करें:

public Object clone() { 
    CurrentClass newObject = new CurrentClass(); 

    newObject.field1 = this.field1; // for simple types: int, long, etc 
    newObject.referenceField = this.referenceField.clone(); // for agregate objects or references. 
    return newObject; 
} 

निष्कर्ष: घोषित एक सार्वजनिक क्लोन विधि। यदि आप फ़ील्ड कॉपी कॉल सुपर द्वारा फ़ील्ड के रूप में डिफ़ॉल्ट कार्यान्वयन करना चाहते हैं और क्लास को क्लोनेबल के रूप में चिह्नित करें यदि आप केवल कस्टम क्लोनिंग चाहते हैं तो आप क्लोनेबल मार्क को अनदेखा कर सकते हैं।

+0

अच्छा है, लेकिन मैंने आदिम प्रकार को एक-एक करके क्लोन किया है, मुझे यह नहीं चाहिए। मैं उन नए डेटा प्रकारों को क्लोन करना चाहता हूं, बिना "newObject.field1 = this.field1;" – Johanna

+0

इस प्रकार क्लोन तंत्र काम करता है :-)। यदि आप कुछ और चाहते हैं तो आपको इसे स्वयं लागू करने की आवश्यकता है (कोड जनरेशन एला एएसएम और/या प्रतिबिंब के साथ)। –

+1

इसे क्लोन में किसी ऑब्जेक्ट को खराब अभ्यास माना जाता है। नए क्लोन उदाहरण प्राप्त करने के लिए आपको super.clone() का उपयोग करना चाहिए। –

11

एक वर्ग cloneable बनाने के लिए मानक पैटर्न है:

  1. लागू Cloneable
  2. अवहेलना clone() विधि और इसे जनता
  3. clone() में कॉल super.clone() बनाने के लिए और फिर उसकी प्रतिलिपि किसी भी परिवर्तनशील वस्तु के राज्य

आपको नहीं एक नई वस्तु बनाएं new गाओ। एक नया उदाहरण के लिए super.clone() पर कॉल करने का उचित तरीका है। Object का clone() विशेष है और ऑब्जेक्ट की एक नई प्रति बना देगा और इसके आदिम फ़ील्ड और संदर्भों की प्रतिलिपि बनाएगा।

उदाहरण के लिए:

public class Person implements Cloneable { 
    protected String name; 
    // Note that overridden clone is public 
    public Object clone() { 
     Person clone = (Person)super.clone(); 
     // No need to copy name as the reference will be 
     // copied by Object's clone and String is immutable 
     return clone; 
    } 
} 

public class Employee extends Person { 
    protected int id; 
    protected java.awt.Point location; 
    public Object clone() { 
     Employee clone = (Employee)super.clone(); 
     // No need to copy id as Object's clone has already copied it 
     // Need to clone location as Point is mutable and could change 
     clone.location = location.clone(); 
     return clone; 
    } 
} 
+0

सच है। आश्चर्य है कि आप व्यक्ति के बच्चों को क्लोनबल होने की आवश्यकता कैसे व्यक्त करते हैं - या सामान्य रूप से: मांग पर खुद को कॉपी करें? क्या क्लोनेबल सुपरक्लास होना पर्याप्त है? – akarnokd

+1

सभी उप-वर्गों में माता-पिता के इंटरफेस का उत्तराधिकारी होता है। तो व्यक्ति क्लोनबल है। –

5

मुझे लगता है कि वर्तमान हरी जवाब बुरा है, तो आप क्यों पूछ सकते हैं?

  • यह कोड
  • का एक बहुत यह कॉपी करने के लिए सभी क्षेत्रों की सूची है और इस
  • यह जब क्लोन() (यह क्या क्लोन है का उपयोग कर सूचियाँ लिए काम नहीं करेगा करने के लिए आवश्यक है कि आप कहते हैं() HashMap का कहना है के लिए: रिटर्न इस HashMap उदाहरण के एक उथले प्रतिलिपि:। कुंजी और valuesthemselves क्लोन नहीं कर रहे हैं) ताकि आप इसे मैन्युअल रूप से कर रही अंत (यह मुझे रोने बनाता है)

ओह और जिस तरह से क्रमबद्धता भी बुरा है , आपको पूरे स्थान पर Serializable जोड़ना पड़ सकता है (यह मुझे सीआर भी बनाता है वाई)।

तो समाधान क्या है:

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

Cloner cloner=new Cloner(); 
XX clone = cloner.deepClone(someObjectOfTypeXX); 

http://code.google.com/p/cloning/

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