जावा: गहरी क्लोनिंग / एक उदाहरण की प्रतिलिपि बनाने के लिए अनुशंसित समाधान


176

मुझे आश्चर्य हो रहा है कि जावा में गहरी क्लोन / उदाहरण की प्रतिलिपि बनाने का एक अनुशंसित तरीका है।

मेरे पास 3 समाधान हैं, लेकिन मुझे कुछ याद हो सकता है, और मैं आपकी राय लेना चाहूंगा

संपादित करें: Bohzo प्रस्तावक और परिष्कृत प्रश्न शामिल करें: यह उथले क्लोनिंग की तुलना में गहरे क्लोनिंग के बारे में अधिक है।

यह स्वयं करो:

गुण के बाद हाथ के गुणों द्वारा क्लोन को कोड करें और जांचें कि उत्परिवर्तित उदाहरणों को भी क्लोन किया गया है।
समर्थक:
- क्या किया जाएगा का नियंत्रण
- त्वरित निष्पादन
विपक्ष:
- लिखने और बनाए रखने के लिए थकाऊ
- बग प्रवण (कॉपी / पेस्ट विफलता, लापता संपत्ति, पुन: असाइन किए गए परिवर्तनशील संपत्ति)

प्रतिबिंब का उपयोग करें:

अपने स्वयं के प्रतिबिंब उपकरणों के साथ या एक बाहरी सहायक (जैसे जकार्ता आम-फलियां) के साथ एक सामान्य प्रतिलिपि विधि लिखना आसान है जो एक पंक्ति में काम करेगा।
समर्थक:
- लिखने में आसान
- रखरखाव रखरखाव नहीं
:
- जो भी होता है उसका कम नियंत्रण
- अगर प्रतिबिंब उपकरण उप वस्तुओं को भी क्लोन नहीं करता है तो उत्परिवर्तित वस्तु के साथ बग प्रवण होता है
- धीमा निष्पादन

क्लोन फ्रेमवर्क का उपयोग करें:

एक फ्रेमवर्क का उपयोग करें जो इसे आपके लिए करता है, जैसे:
कॉमन्स-लैंग सीरियलाइज़ेशन यूटिल्स
जावा डीप क्लोनिंग लाइब्रेरी
डोज़र
कीटो

प्रो:
- समान प्रतिबिंब
- जो वास्तव में क्लोन किया जाएगा उस पर अधिक नियंत्रण।
विपक्ष:
- हर उत्परिवर्ती उदाहरण पूरी तरह से क्लोन है, यहां तक ​​कि पदानुक्रम के अंत में
- निष्पादित करने के लिए बहुत धीमा हो सकता है

रनटाइम पर क्लोन लिखने के लिए बायटेकोड इंस्ट्रूमेंटेशन का उपयोग करें

javassit , BCEL या cglib का उपयोग एक हाथ से लिखे गए उपवास के रूप में एक समर्पित क्लोनर बनाने के लिए किया जा सकता है। कोई व्यक्ति इस उद्देश्य के लिए इनमें से किसी एक उपकरण का उपयोग करके एक परिवाद जानता है?

मुझे यहाँ क्या याद आया?
तुम किसकी सिफारिश करना चाहोगे ?

धन्यवाद।


1
जाहिरा तौर पर जावा डीप क्लोनिंग लाइब्रेरी यहां चली गई: code.google.com/p/cloning
Mr_and_Mrs_D

जवाबों:


155

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

  • commons-lang SerializationUtils - क्रमांकन का उपयोग करना - यदि सभी वर्ग आपके नियंत्रण में हैं और आप कार्यान्वयन के लिए बाध्य कर सकते हैं Serializable

  • जावा डीप क्लोनिंग लाइब्रेरी - प्रतिबिंब का उपयोग करते हुए - उन मामलों में जब कक्षाएं या ऑब्जेक्ट जिन्हें आप क्लोन करना चाहते हैं वे आपके नियंत्रण से बाहर हैं (एक 3 पार्टी लाइब्रेरी) और आप उन्हें लागू नहीं कर सकते हैं Serializable, या उन मामलों में जिन्हें आप लागू नहीं करना चाहते हैं। Serializable

उथले क्लोनिंग के लिए (केवल पहले स्तर के गुण क्लोन):

मैंने जानबूझकर "डू-इट-योरस" विकल्प को छोड़ दिया - एपीआई के ऊपर एक अच्छा नियंत्रण प्रदान करता है कि क्या करना है और क्या नहीं करना है (उदाहरण के लिए उपयोग करना transient, या String[] ignoreProperties), इसलिए पहिया को सुदृढ़ करना पसंद नहीं है।


धन्यवाद Bozho, यह मूल्यवान है। और मैं आपसे DIY विकल्प के बारे में सहमत हूँ! क्या तुमने कभी commons serialzation और / या गहरी क्लोनिंग की कोशिश की है? परिधियों के बारे में क्या?
गिलियूम

हां, मैंने उपरोक्त सभी विकल्पों का उपयोग किया है, उपरोक्त कारणों के लिए :) केवल क्लोनिंग लाइब्रेरी में कुछ मुद्दे थे जब CGLIB परदे के पीछे शामिल थे, और कुछ वांछित कार्यक्षमता याद आती थी, लेकिन मुझे लगता है कि अब इसे ठीक किया जाना चाहिए।
बोहजो

अरे, अगर मेरा Entity संलग्न है और मेरे पास आलसी चीजें हैं, तो SerializationUtils क्या आलसी गुणों के लिए डेटाबेस की जांच करता है? Cuz यह वही है जो मैं चाहता हूं, और यह नहीं है!
कोस्मिन कॉस्मिन

यदि आपके पास एक सक्रिय सत्र है - हाँ, यह करता है।
बूझो

@Bozho तो आपका मतलब है कि अगर बीन के भीतर की सभी वस्तुएं क्रमिक रूप से लागू हो रही हैं, तो org.apache.commons.beanutils.BeanUtils.cloneBean (obj) एक गहरी कॉपी करेगा?
हॉप

36

जोशुआ बलोच की पुस्तक में "आइटम 10: ओवरराइड क्लोन जूडलीली" नाम से एक पूरा अध्याय है , जिसमें वह इस बात पर ध्यान देता है कि अधिकांश भाग के लिए क्लोन को ओवरराइड करना एक बुरा विचार क्यों है क्योंकि इसके लिए जावा कल्पना कई समस्याएं पैदा करती है।

वह कुछ विकल्प प्रदान करता है:

  • एक निर्माता के स्थान पर एक कारखाने पैटर्न का उपयोग करें:

         public static Yum newInstance(Yum yum);
  • प्रतिलिपि निर्माता का उपयोग करें:

         public Yum(Yum yum);

जावा में सभी संग्रह कक्षाएं कॉपी कंस्ट्रक्टर का समर्थन करती हैं (उदाहरण के लिए नई ArrayList (l);)


1
माना। मेरे प्रोजेक्ट में मैंने एक Copyableइंटरफ़ेस परिभाषित किया जिसमें एक getCopy()विधि शामिल है । बस प्रोटोटाइप पैटर्न का उपयोग मैन्युअल रूप से करें।
gpampara

वैसे मैं क्लोन करने योग्य इंटरफ़ेस के बारे में नहीं पूछ रहा था, लेकिन एक गहरी क्लोन / कॉपी ऑपरेशन कैसे करें। एक निर्माता या एक कारखाने के साथ आपको अभी भी अपने स्रोत से अपना नया उदाहरण बनाने की आवश्यकता है।
गिलियूम

@ मुझे लगता है कि आपको गहरी क्लोन / कॉपी शब्दों का उपयोग करने में सावधानी बरतने की आवश्यकता है। क्लोन और जावा में कॉपी का मतलब एक ही बात नहीं है। जावा युक्ति का इस बारे में कहना अधिक है .... मुझे लगता है कि आप जो बता सकते हैं उससे एक गहरी प्रति चाहते हैं।
LeWoody

ओके जावा युक्ति सटीक है कि कोई क्लोन क्या है ... लेकिन हम क्लोन को अधिक सामान्य अर्थों में भी बोल सकते हैं ... उदाहरण के लिए, बोहो द्वारा अनुशंसित लिब में से एक का नाम 'जावा डीप क्लोनिंग लाइब्रेरी' है ...
गिलाउल

2
@Loodyiii यह newInstance()तरीका और Yumकंस्ट्रक्टर गहरी कॉपी या उथली कॉपी करेगा?
गीक

9

संस्करण 2.07 क्रायो उथले / गहरी क्लोनिंग का समर्थन करता है :

Kryo kryo = new Kryo();
SomeClass someObject = ...
SomeClass copy1 = kryo.copy(someObject);
SomeClass copy2 = kryo.copyShallow(someObject);

Kryo तेज है, उनके पेज पर आपको उन कंपनियों की सूची मिल सकती है जो उत्पादन में इसका उपयोग करती हैं।


5

मेमोरी में XStream toXML / fromXML का उपयोग करें। अत्यधिक तेज और लंबे समय से आसपास रहा है और मजबूत हो रहा है। वस्तुओं को सीरियल करने की आवश्यकता नहीं है और आपके पास प्रतिबिंब का उपयोग नहीं है (हालांकि XStream करता है)। XStream वैरिएबल को एक ही वस्तु को इंगित कर सकता है और गलती से उदाहरण की दो पूर्ण प्रतियां नहीं बना सकता है। इस तरह के बहुत सारे विवरण पिछले कुछ वर्षों में सामने आए हैं। मैंने इसे कई सालों तक इस्तेमाल किया है और यह एक जाना है। यह उपयोग करने में उतना ही आसान है जितना आप कल्पना कर सकते हैं।

new XStream().toXML(myObj)

या

new XStream().fromXML(myXML)

क्लोन बनाने के लिए,

new XStream().fromXML(new XStream().toXML(myObj))

अधिक रसीला:

XStream x = new XStream();
Object myClone = x.fromXML(x.toXML(myObj));

3

जटिल वस्तुओं के लिए और जब प्रदर्शन महत्वपूर्ण नहीं होता है तो मैं वस्तु का उपयोग करके पाठ को वस्तु को क्रमबद्ध करने के लिए प्रयोग करता हूं , फिर नई वस्तु प्राप्त करने के लिए पाठ का वर्णन करता हूं

गसन जो प्रतिबिंब पर आधारित है, ज्यादातर मामलों में काम करेगा, सिवाय इसके कि transientखेतों को कॉपी नहीं किया जाएगा और वस्तुओं को कारण के साथ परिपत्र संदर्भ के साथ StackOverflowError

public static <ObjectType> ObjectType Copy(ObjectType AnObject, Class<ObjectType> ClassInfo)
{
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(AnObject);
    ObjectType newObject = gson.fromJson(text, ClassInfo);
    return newObject;
}
public static void main(String[] args)
{
    MyObject anObject ...
    MyObject copyObject = Copy(o, MyObject.class);

}

2

निर्भर करता है।

गति के लिए, DIY का उपयोग करें। बुलेटप्रूफ के लिए, प्रतिबिंब का उपयोग करें।

BTW, क्रमांकन refl के समान नहीं है, क्योंकि कुछ ऑब्जेक्ट ओवरराइड क्रमांकन विधियाँ प्रदान कर सकते हैं (readObject / writeObject) और वे छोटी गाड़ी हो सकती हैं


1
प्रतिबिंब बुलेट प्रूफ नहीं है: यह कुछ ऐसी स्थिति में ले जा सकता है जहां आपकी क्लोन की गई वस्तु का आपके स्रोत से संदर्भ होता है ... यदि स्रोत बदल जाता है, तो क्लोन भी बदल जाएगा!
गिलाउम

1

मैं एक अच्छा हैशकोड () और बराबर () विधि के साथ संयुक्त रूप से DIY तरीका सुझाता हूं, जो इकाई परीक्षण में प्रमाण के लिए आसान होना चाहिए।


ठीक है, आलसी मुझे बहुत डांटते हैं जब इस तरह के डमी कोड बनाते हैं। लेकिन यह समझदार पथ की तरह लग रहा है ...
गिलियूम

2
खेद है, लेकिन DIY जाने का रास्ता है ही , अगर कोई अन्य समाधान you..which के लिए उपयुक्त है है लगभग कभी
Bozho

1

मैं उन सभी संदर्भों पर Object.clone (), कॉल super.clone () और कॉल ref = ref.clone () को ओवरराइड करने का सुझाव दूंगा, जिन्हें आप कॉपी करना चाहते हैं। यह कम या ज्यादा है इसे अपने आप से संपर्क करें लेकिन थोड़ा कम कोडिंग की आवश्यकता है।


2
यह (टूटी हुई) क्लोन विधि की कई समस्याओं में से एक है: एक वर्ग पदानुक्रम में आपको हमेशा सुपर.क्लोन () कॉल करना होगा, जिसे आसानी से भुलाया जा सकता है, इसीलिए मैं एक कॉपी कंस्ट्रक्टर का उपयोग करना पसंद करूंगा।
हेल्मेथेथोड

0

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

public static class Obj implements Serializable {
    public int a, b;
    public Obj(int a, int b) {
        this.a = a;
        this.b = b;
    }
}

और फिर इस फ़ंक्शन का उपयोग करें:

public static Object deepClone(Object object) {
    try {
        ByteArrayOutputStream baOs = new ByteArrayOutputStream();
        ObjectOutputStream oOs = new ObjectOutputStream(baOs);
        oOs.writeObject(object);
        ByteArrayInputStream baIs = new ByteArrayInputStream(baOs.toByteArray());
        ObjectInputStream oIs = new ObjectInputStream(baIs);
        return oIs.readObject();
    }
    catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

इस तरह: Obj newObject = (Obj)deepClone(oldObject);

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.