2010-04-26 17 views
10

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

उदाहरण निम्नानुसार है।

public class Example { 

private static class ContainerClass implements java.io.Serializable { 
    private ReferencedClass obj; 
    public ReferencedClass get() { 
    return obj; 
    } 
    public void set(ReferencedClass obj) { 
    this.obj = obj; 
    } 
} 

private static class ReferencedClass implements java.io.Serializable { 
    private int i = 0; 
    public int get() { 
    return i; 
    } 
    public void set(int i) { 
    this.i = i; 
    } 
} 

public static void main(String[] args) throws Exception { 
    //Initialise the classes 
    ContainerClass test1 = new ContainerClass(); 
    ContainerClass test2 = new ContainerClass(); 
    ReferencedClass ref = new ReferencedClass(); 

    //Make both container class point to the same reference 
    test1.set(ref); 
    test2.set(ref); 

    //This does what we expect: setting the integer in one (way of accessing the) referenced class sets it in the other one 
    test1.get().set(1234); 
    System.out.println(Integer.toString(test2.get().get())); 

    //Now serialise the container classes 
    java.io.ObjectOutputStream os = new java.io.ObjectOutputStream(new java.io.FileOutputStream("C:\\Users\\Public\\test1.ser")); 
    os.writeObject(test1); 
    os.close(); 
    os = new java.io.ObjectOutputStream(new java.io.FileOutputStream("C:\\Users\\Public\\test2.ser")); 
    os.writeObject(test2); 
    os.close(); 

    //And deserialise them 
    java.io.ObjectInputStream is = new java.io.ObjectInputStream(new java.io.FileInputStream("C:\\Users\\Public\\test1.ser")); 
    ContainerClass test3 = (ContainerClass)is.readObject(); 
    is.close(); 
    is = new java.io.ObjectInputStream(new java.io.FileInputStream("C:\\Users\\Public\\test2.ser")); 
    ContainerClass test4 = (ContainerClass)is.readObject(); 
    is.close(); 

    //We expect the same thing as before, and would expect a result of 4321, but this doesn't happen as the referenced objects are now separate instances 
    test3.get().set(4321); 
    System.out.println(Integer.toString(test4.get().get())); 
} 

} 
+0

किसी भी भाषा –

उत्तर

3

readResolve() method इस अनुमति देता है (बेशक, पहले आप कैसे आप तय करते हैं जो वस्तुओं "एक ही" के लिए हैं जा रहे हैं परिभाषित करने के लिए है)। लेकिन ऑब्जेक्टऑट/इनपुटस्ट्रीम दोनों ऑब्जेक्ट्स को एक ही फाइल में क्रमबद्ध करने के लिए बहुत आसान होगा - ऑब्जेक्टऑट/इनपुटस्ट्रीम उन सभी ऑब्जेक्ट्स का रिकॉर्ड रखता है जो इसे क्रमबद्ध/deserialized है और केवल उन वस्तुओं के संदर्भों को संग्रहित और वापस कर देगा जो पहले से ही देख चुके हैं।

+0

(और शायद 'लिखने की जगह') में deserializing ऑब्जेक्ट का झुकाव +1 –

+0

मोटे तौर पर, कारण यह है कि मैं ऐसा करने की कोशिश कर रहा हूं क्योंकि मेरे पास एक फ़ाइल है जिसमें कई सत्रों में बदलाव होने की संभावना नहीं है आवेदन के, और एक डेटा जिसमें अनुप्रयोग के एक सत्र के लिए विशिष्ट है। इनके बीच पार-संदर्भ हैं लेकिन मैं उन्हें तर्कसंगत रूप से अलग रखना चाहता हूं। – Kidburla

0

मैंने ऐसा कुछ एप्लिकेशन सर्वर/ऑब्जेक्ट डेटाबेस के लिए किया है जो मैं बना रहा हूं। आपकी आवश्यकताओं क्या हैं - आपको ऐसा करने की आवश्यकता क्यों है? यदि आपकी आवश्यकताएं किसी एप्लिकेशन सर्वर से कम कुछ हैं, तो शायद कुछ अन्य डिज़ाइन इसे आसान बना देंगे।


आप फिर भी आगे बढ़ना चाहते हैं, तो यहाँ इसे कैसे करना है:

सबसे पहले आप ObjectOutputStream.replaceObject() और ObjectInputStream.resolveObject() तरीकों अधिभावी द्वारा क्रमबद्धता प्रक्रिया में हुक करने की जरूरत है। उदाहरण के लिए मेरे ObjectSerializer देखें। वस्तुओं की उस तरह सामान्यतः संस्थाओं कहा जाता है -

जब आप वस्तुओं को क्रमानुसार, आप प्रत्येक वस्तु के उदाहरण है कि आप एक अद्वितीय पहचान करना चाहते हैं के लिए एक अद्वितीय ID सौंपनी होगी। जब ऑब्जेक्ट अन्य इकाइयों को संदर्भित करता है, तो आपको उन अन्य इकाइयों को प्लेसहोल्डर ऑब्जेक्ट से प्रतिस्थापित करना होगा जिसमें निर्दिष्ट इकाई की आईडी हो।

फिर जब वस्तुओं deserialized कर रहे हैं, तो आप उन प्लेसहोल्डर वस्तुओं में से प्रत्येक के वास्तविक इकाई वस्तु जो कि आईडी है के साथ बदलना होगा। आपको इकाई ऑब्जेक्ट इंस्टेंस का ट्रैक रखने की आवश्यकता है जो स्मृति और उनकी आईडी में लोड हो चुके हैं, ताकि प्रत्येक आईडी के लिए केवल एक बार उदाहरण बनाया जा सके। अगर इकाई अभी तक स्मृति में लोड नहीं हुई है, तो आपको इसे सहेजने से इसे लोड करना होगा। उदाहरण के लिए मेरे EntityManager देखें।

यदि आप आलसी लोडिंग करना चाहते हैं, तो ऑब्जेक्ट में पूरे ऑब्जेक्ट ग्राफ़ को लोड करने से बचने के लिए, आपको transparent references जैसा कुछ करना होगा। उनके कार्यान्वयन here देखें। आपको लगता है कि अब तक हो रही है, तो आप के रूप में अच्छी अपने प्रोजेक्ट से उन भागों (संकुल entities, entities.tref, serial और शायद यह भी context) की प्रतिलिपि सकता है - यह एक अनुमोदक लाइसेंस है - और अपनी आवश्यकताओं फिट करने के लिए उन्हें संशोधित (यानी सामान हटाने आप जरूरत नहीं है)। के रूप में यह आपको अपना इच्छित के साथ "नकल" वस्तु को बदलने के लिए अनुमति देता है

1

ऊपर जवाब की तरह, readResolve, कुंजी है।

अपने वर्ग के उपकरण हैशकोड() और बराबर() को मानते हुए, आप एक स्थिर WeakHashMap बनाकर deduplication लागू करते हैं जो अभी भी स्मृति में बनाई गई वस्तुओं के सभी संदर्भ रखता है। जैसे

class ReferencedClass implements Serializable 
{ 
    static private Map<ReferencedClass, Reference<ReferencedClass>> map = new WeakHashMap<ReferencedClass, Reference<ReferencedClass>>; 

    static public ReferencedClass findOriginal(ReferencedClass obj) 
    { 
     WeakReference<ReferencedClass> originalRef = map.get(obj); 
     ReferencedClass original = originalRef==null ? null : originalRef.get(); 
     if (original==null) 
     { 
      original = obj; 
      map.put(original, new WeakReference<ReferencedClass>(original)); 
     } 
     return original; 
    } 

    static public ReferencedClass() 
    { 
     findOriginal(this); 
    } 

    private Object readResolve() 
    { 
     return findOriginal(this); 
    } 
} 

जब deserializing, readResolve() वर्तमान मूल उदाहरण लाने के लिए RerencedClass.findOriginal(this) कहता है। यदि इस वर्ग के उदाहरण केवल deserialization द्वारा बनाए जाते हैं, तो यह इस तरह काम करेगा।यदि आप ऑब्जेक्ट्स (नए ऑपरेटर का उपयोग करके) भी बना रहे हैं, तो आपके कन्स्ट्रक्टर को यह पता चलाना चाहिए कि यह मूल है, ताकि वे ऑब्जेक्ट को पूल में भी जोड़ सकें।

जगहों में इन परिवर्तनों के साथ, ContainerClass उदाहरण दोनों ReferenceClass उदाहरण दोनों को इंगित करेंगे, भले ही वे उदासीन रूप से deserialized थे।

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