मुझे पता है कि यह प्रश्न वास्तव में पुराना है और इसका एक स्वीकृत उत्तर है, लेकिन जैसा कि यह Google खोज में बहुत अधिक है, मैंने सोचा कि मैं वजन करूंगा क्योंकि कोई भी उत्तर तीन मामलों को शामिल नहीं करता है जिन्हें मैं महत्वपूर्ण मानता हूं - मेरे दिमाग में इन के लिए प्राथमिक उपयोग तरीकों। बेशक, सभी मानते हैं कि वास्तव में कस्टम क्रमांकन प्रारूप की आवश्यकता है।
उदाहरण के लिए, संग्रह कक्षाएं लें। किसी लिंक की गई सूची या BST के डिफ़ॉल्ट क्रमांकन के परिणामस्वरूप बहुत कम प्रदर्शन प्राप्त होता है, जिससे तत्वों को क्रम में क्रमबद्ध करने की तुलना में बहुत कम प्रदर्शन होता है। यह और भी सच है अगर कोई संग्रह एक प्रक्षेपण या एक दृश्य है - एक बड़ी संरचना का संदर्भ रखता है जितना कि वह अपने सार्वजनिक एपीआई द्वारा उजागर करता है।
यदि सीरियल किए गए ऑब्जेक्ट में अपरिवर्तनीय फ़ील्ड हैं जिन्हें कस्टम क्रमांकन की आवश्यकता है, तो मूल समाधान writeObject/readObject
अपर्याप्त है, क्योंकि लिखित धारा के भाग को पढ़ने से पहले deserialized ऑब्जेक्ट बनाया जाता है writeObject
। लिंक की गई सूची का यह न्यूनतम क्रियान्वयन करें:
public class List<E> extends Serializable {
public final E head;
public final List<E> tail;
public List(E head, List<E> tail) {
if (head==null)
throw new IllegalArgumentException("null as a list element");
this.head = head;
this.tail = tail;
}
//methods follow...
}
इस संरचना को head
प्रत्येक लिंक के क्षेत्र को पुनरावर्ती रूप से लिखते हुए क्रमबद्ध किया जा सकता है , उसके बाद एक null
मान। इस तरह के प्रारूप का वर्णन करना हालांकि असंभव हो जाता है: readObject
सदस्य फ़ील्ड्स (अब निश्चित किया गया null
) के मूल्यों को बदल नहीं सकता है । यहाँ आओ writeReplace
/ readResolve
जोड़ी:
private Object writeReplace() {
return new Serializable() {
private transient List<E> contents = List.this;
private void writeObject(ObjectOutputStream oos) {
List<E> list = contents;
while (list!=null) {
oos.writeObject(list.head);
list = list.tail;
}
oos.writeObject(null);
}
private void readObject(ObjectInputStream ois) {
List<E> tail = null;
E head = ois.readObject();
if (head!=null) {
readObject(ois); //read the tail and assign it to this.contents
this.contents = new List<>(head, this.contents)
}
}
private Object readResolve() {
return this.contents;
}
}
}
मुझे खेद है अगर उपरोक्त उदाहरण संकलन (या काम) नहीं करता है, लेकिन उम्मीद है कि यह मेरी बात को स्पष्ट करने के लिए पर्याप्त है। यदि आपको लगता है कि यह एक बहुत दूर का उदाहरण है तो कृपया याद रखें कि जेवीएम पर कई कार्यात्मक भाषाएं चलती हैं और यह दृष्टिकोण उनके मामले में आवश्यक हो जाता है।
हम वास्तव में एक अलग वर्ग की एक वस्तु को अलग करना चाह सकते हैं, जितना हमने लिखा है ObjectOutputStream
। यह एक java.util.List
सूची कार्यान्वयन जैसे विचारों के साथ होगा जो लंबे समय से एक स्लाइस को उजागर करता है ArrayList
। जाहिर है, पूरी बैकिंग सूची को क्रमबद्ध करना एक बुरा विचार है और हमें केवल देखे गए स्लाइस से तत्वों को लिखना चाहिए। हालाँकि इस पर रोक क्यों है और निर्जनता के बाद अप्रत्यक्ष स्तर बेकार है? हम केवल धारा से तत्वों को एक में पढ़ सकते हैं ArrayList
और इसे सीधे हमारे दृश्य वर्ग में लपेटने के बजाय वापस कर सकते हैं।
वैकल्पिक रूप से, एक समान प्रतिनिधि वर्ग को क्रमबद्धता के लिए समर्पित होना एक डिजाइन विकल्प हो सकता है। एक अच्छा उदाहरण हमारे क्रमांकन कोड का पुन: उपयोग करना होगा। उदाहरण के लिए, यदि हमारे पास एक बिल्डर वर्ग (स्ट्रिंग के लिए StringBuilder के समान) है, तो हम एक क्रमांकन प्रतिनिधि लिख सकते हैं जो किसी भी संग्रह को धारा में एक खाली बिल्डर लिखकर क्रमबद्ध करता है, उसके बाद संग्रह का आकार और तत्वों द्वारा colection के पुनरावृत्ति द्वारा लौटाया जाता है। देशीकरण में बिल्डर को पढ़ना, सभी बाद में पढ़ने वाले तत्वों को शामिल करना और build()
प्रतिनिधियों से अंतिम परिणाम वापस करना शामिल होगा readResolve
। उस मामले में हमें केवल संग्रह पदानुक्रम के मूल वर्ग में क्रमांकन लागू करने की आवश्यकता होगी, और वर्तमान या भविष्य के कार्यान्वयन से कोई अतिरिक्त कोड की आवश्यकता नहीं होगी, बशर्ते वे अमूर्त लागू करेंiterator()
औरbuilder()
विधि (उसी प्रकार के संग्रह को फिर से बनाने के लिए उत्तरार्द्ध - जो अपने आप में एक बहुत ही उपयोगी विशेषता होगी)। एक अन्य उदाहरण एक वर्ग पदानुक्रम होगा जिस कोड को हम पूरी तरह से नियंत्रित नहीं करते हैं - एक तीसरे पक्ष के पुस्तकालय से हमारा आधार वर्ग (तों) किसी भी संख्या में निजी क्षेत्रों में हो सकता है, जिनके बारे में हम कुछ भी नहीं जानते हैं और जो एक संस्करण से दूसरे संस्करण में बदल सकते हैं, ब्रेकिंग हमारे अनुक्रमित वस्तुओं। उस स्थिति में डेटा लिखना और ऑब्जेक्ट को पुन: डिजायरलाइज़ेशन पर फिर से बनाना सुरक्षित होगा।
String.CaseInsensitiveComparator.readResolve()