एक गहरी ऑब्जेक्ट कॉपी फ़ंक्शन को लागू करना थोड़ा मुश्किल है। मूल वस्तु और क्लोन किए गए शेयर को सुनिश्चित करने के लिए आप क्या कदम उठाते हैं?
एक गहरी ऑब्जेक्ट कॉपी फ़ंक्शन को लागू करना थोड़ा मुश्किल है। मूल वस्तु और क्लोन किए गए शेयर को सुनिश्चित करने के लिए आप क्या कदम उठाते हैं?
जवाबों:
एक सुरक्षित तरीका वस्तु को क्रमबद्ध करना है, फिर deserialize। यह सुनिश्चित करता है कि सब कुछ एक नया संदर्भ है।
यहाँ एक लेख है कि यह कैसे कुशलतापूर्वक किया जाए।
कैविट्स: वर्गों के लिए यह संभव है कि क्रमांकन को ओवरराइड किया जाए ताकि नए उदाहरण न बन सकें, उदाहरण के लिए सिंगलटन। यदि आपकी कक्षाएं सीरियलाइज़्ड नहीं हैं, तो भी यह निश्चित रूप से काम नहीं करता है।
कुछ लोगों ने उपयोग या ओवरराइडिंग का उल्लेख किया है Object.clone()
। यह मत करो। Object.clone()
कुछ प्रमुख समस्याएं हैं, और ज्यादातर मामलों में इसका उपयोग हतोत्साहित किया जाता है। कृपया पूर्ण उत्तर के लिए जोशुआ बलोच द्वारा " प्रभावी जावा " से आइटम 11 देखें । मेरा मानना है कि आप सुरक्षित रूप Object.clone()
से आदिम प्रकार सरणियों पर उपयोग कर सकते हैं , लेकिन इसके अलावा आपको क्लोन का सही उपयोग और ओवरराइडिंग के बारे में विवेकपूर्ण होने की आवश्यकता है।
योजनाएँ जो क्रमबद्धता पर निर्भर करती हैं (XML या अन्यथा) कुडली हैं।
यहां कोई आसान जवाब नहीं है। यदि आप किसी ऑब्जेक्ट को डीप कॉपी करना चाहते हैं, तो आपको ऑब्जेक्ट ग्राफ को ट्रेस करना होगा और ऑब्जेक्ट की कॉपी कंस्ट्रक्टर या स्टैटिक फैक्ट्री विधि के माध्यम से प्रत्येक चाइल्ड ऑब्जेक्ट को स्पष्ट रूप से कॉपी करना होगा, जो कि चाइल्ड ऑब्जेक्ट को गहरी कॉपी करता है। Immutables (जैसे String
s) को कॉपी करने की आवश्यकता नहीं है। एक तरफ के रूप में, आपको इस कारण से अपरिवर्तनीयता का पक्ष लेना चाहिए।
आप फ़ाइलों को बनाए बिना क्रमांकन के साथ एक गहरी प्रतिलिपि बना सकते हैं।
आपकी वस्तु जिसे आप कॉपी करना चाहते हैं, उसकी आवश्यकता होगी implement serializable
। यदि वर्ग अंतिम नहीं है या संशोधित नहीं किया जा सकता है, तो कक्षा का विस्तार करें और क्रमबद्ध लागू करें।
अपनी कक्षा को बाइट की एक धारा में परिवर्तित करें:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
अपनी कक्षा को बाइट की एक धारा से पुनर्स्थापित करें:
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
(Object) object = (Object) new ObjectInputStream(bais).readObject();
instance
इस मामले में गैर-परिवर्तनीय वर्ग की संपत्ति को कैसे अनुक्रमित किया जाएगा, गैर-सीरियल करने योग्य है?
आप org.apache.commons.lang3.SerializationUtils.clone(T)
अपाचे कॉमन्स लैंग का उपयोग करके एक सीरियल-आधारित डीप क्लोन कर सकते हैं , लेकिन सावधान रहें- प्रदर्शन लाजिमी है।
सामान्य तौर पर, क्लोनिंग की आवश्यकता वाले ऑब्जेक्ट ग्राफ में ऑब्जेक्ट के प्रत्येक वर्ग के लिए अपने स्वयं के क्लोन तरीकों को लिखना सबसे अच्छा अभ्यास है।
org.apache.commons.lang.SerializationUtils
गहरी कॉपी को लागू करने का एक तरीका यह है कि प्रत्येक संबद्ध वर्ग में कॉपी कंस्ट्रक्टरों को जोड़ा जाए। एक कॉपी निर्माता अपने एकल तर्क के रूप में 'इस' का एक उदाहरण लेता है और उससे सभी मूल्यों को कॉपी करता है। कुछ काम है, लेकिन बहुत सीधा और सुरक्षित है।
संपादित करें: ध्यान दें कि आपको फ़ील्ड पढ़ने के लिए एक्सेसर विधियों का उपयोग करने की आवश्यकता नहीं है। आप सभी फ़ील्ड को सीधे एक्सेस कर सकते हैं क्योंकि स्रोत का उदाहरण हमेशा कॉपी कंस्ट्रक्टर के साथ उदाहरण के समान होता है। स्पष्ट लेकिन अनदेखी हो सकती है।
उदाहरण:
public class Order {
private long number;
public Order() {
}
/**
* Copy constructor
*/
public Order(Order source) {
number = source.number;
}
}
public class Customer {
private String name;
private List<Order> orders = new ArrayList<Order>();
public Customer() {
}
/**
* Copy constructor
*/
public Customer(Customer source) {
name = source.name;
for (Order sourceOrder : source.orders) {
orders.add(new Order(sourceOrder));
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
संपादित करें: ध्यान दें कि कॉपी कंस्ट्रक्टर्स का उपयोग करते समय आपको उस ऑब्जेक्ट के रनटाइम प्रकार को जानना होगा जो आप कॉपी कर रहे हैं। उपरोक्त दृष्टिकोण के साथ आप आसानी से एक मिश्रित सूची की प्रतिलिपि नहीं बना सकते हैं (आप इसे कुछ प्रतिबिंब कोड के साथ करने में सक्षम हो सकते हैं)।
Toyota
, तो आपका कोड Car
गंतव्य सूची में डाल देगा । उचित क्लोनिंग के लिए आम तौर पर यह आवश्यक होता है कि वर्ग एक वर्चुअल फैक्ट्री विधि प्रदान करे, जिसका अनुबंध बताता है कि यह अपनी कक्षा की एक नई वस्तु लौटाएगा; कॉपी कॉन्ट्रैक्टर खुद protected
यह सुनिश्चित करने के लिए होना चाहिए कि इसका उपयोग केवल उन वस्तुओं के निर्माण के लिए किया जाएगा, जिनके सटीक प्रकार का मिलान होने वाली वस्तु से मेल खाता है)।
आप एक पुस्तकालय का उपयोग कर सकते हैं जिसमें एक साधारण एपीआई है, और प्रतिबिंब के साथ अपेक्षाकृत तेजी से क्लोनिंग करता है (क्रमांकन विधियों की तुलना में तेज होना चाहिए)।
Cloner cloner = new Cloner();
MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o
Apache commons किसी वस्तु को गहरी क्लोन करने का तेज़ तरीका प्रदान करता है।
My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);
XStream ऐसे उदाहरणों में वास्तव में उपयोगी है। यहाँ क्लोनिंग करने का एक सरल कोड है
private static final XStream XSTREAM = new XStream();
...
Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));
एक बहुत ही आसान और सरल तरीका है जैक्सन JSON का उपयोग जटिल जावा ऑब्जेक्ट को JSON में क्रमबद्ध करना और इसे वापस पढ़ना।
के लिए स्प्रिंग फ्रेमवर्क उपयोगकर्ताओं। वर्ग का उपयोग करना org.springframework.util.SerializationUtils
:
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}
जटिल वस्तुओं के लिए और जब प्रदर्शन महत्वपूर्ण नहीं होता है, तो मैं गन्स की तरह एक json लाइब्रेरी का उपयोग करता हूं करने के लिए ऑब्जेक्ट को json text को serialize करना है, फिर नए ऑब्जेक्ट को प्राप्त करने के लिए टेक्स्ट को करें।
गन्स जो प्रतिबिंब पर आधारित है, ज्यादातर मामलों में काम करेगा, सिवाय इसके कि transient
खेतों को कॉपी नहीं किया जाएगा और वस्तुओं को कारण के साथ परिपत्र संदर्भ के साथ StackOverflowError
।
public static <T> T copy(T anObject, Class<T> classInfo) {
Gson gson = new GsonBuilder().create();
String text = gson.toJson(anObject);
T newObject = gson.fromJson(text, classInfo);
return newObject;
}
public static void main(String[] args) {
String originalObject = "hello";
String copiedObject = copy(originalObject, String.class);
}
XStream ( http://x-stream.github.io/ ) का उपयोग करें । आप यह भी नियंत्रित कर सकते हैं कि कौन से गुण आप एनोटेशन के माध्यम से अनदेखा कर सकते हैं या संपत्ति के नाम को एक्सस्ट्रीम क्लास में स्पष्ट रूप से निर्दिष्ट कर सकते हैं। इसके अलावा आपको क्लोन करने योग्य इंटरफ़ेस को लागू करने की आवश्यकता नहीं है।
गहरी नकल केवल प्रत्येक वर्ग की सहमति से की जा सकती है। यदि आपका वर्ग पदानुक्रम पर नियंत्रण है तो आप क्लोन करने योग्य इंटरफ़ेस को लागू कर सकते हैं और क्लोन विधि को लागू कर सकते हैं। अन्यथा एक गहरी कॉपी करना सुरक्षित रूप से करना असंभव है क्योंकि ऑब्जेक्ट गैर-डेटा संसाधनों (जैसे डेटाबेस कनेक्शन) को साझा करना भी हो सकता है। हालांकि सामान्य रूप से गहरी नकल को जावा वातावरण में बुरा व्यवहार माना जाता है और उचित डिजाइन प्रथाओं के माध्यम से बचा जाना चाहिए।
import com.thoughtworks.xstream.XStream;
public class deepCopy {
private static XStream xstream = new XStream();
//serialize with Xstream them deserialize ...
public static Object deepCopy(Object obj){
return xstream.fromXML(xstream.toXML(obj));
}
}
1)
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;
}
}
2)
// (1) create a MyPerson object named Al
MyAddress address = new MyAddress("Vishrantwadi ", "Pune", "India");
MyPerson al = new MyPerson("Al", "Arun", address);
// (2) make a deep clone of Al
MyPerson neighbor = (MyPerson)deepClone(al);
यहां आपके MyPerson और MyAddress वर्ग को सीरिलज़ेबल इंटरफ़ेस लागू करना होगा
जैक्सन का उपयोग करके वस्तु को क्रमबद्ध करना और उसे निष्क्रिय करना। इस कार्यान्वयन के लिए सीरियल योग्य श्रेणी को लागू करने के लिए ऑब्जेक्ट की आवश्यकता नहीं है।
<T> T clone(T object, Class<T> clazzType) throws IOException {
final ObjectMapper objMapper = new ObjectMapper();
String jsonStr= objMapper.writeValueAsString(object);
return objMapper.readValue(jsonStr, clazzType);
}