2009-08-29 12 views
22

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

मेरा एपीआई कुछ परिचालनों के लिए ऑब्जेक्ट पहचान पर निर्भर करता है और मुझे आश्चर्य है कि यह क्रमबद्धता द्वारा संरक्षित किया जाएगा या नहीं। यह कहना है: यदि दो मनमाने ढंग से ऑब्जेक्ट्स a और b के लिए, यह क्रमशः a == b सेरियलाइजेशन से पहले है, क्या यह अभी भी deserialization के बाद पकड़ता है?

मुझे कुछ ग्रंथ मिले हैं जो claim the contrary - लेकिन उन्होंने या तो जेआरई के पुराने संस्करण के बारे में लिखा (मुझे केवल 1.6 और शायद 1.5 में दिलचस्पी है), या आरएमआई से संबंधित थे (जो मेरे लिए प्रासंगिक नहीं है)।

documentation ऑब्जेक्ट पहचान के संबंध में बहुत जल्द नहीं है। Sun.com पर technical article का उल्लेख है कि ObjectOutputStream ऑब्जेक्ट्स पर कैशिंग का उपयोग करता है, जो मुझे केवल तभी समझ में आता है जब वस्तु पहचान वास्तव में संरक्षित होती है लेकिन मुझे इस भद्दा सबूत पर भरोसा करने के लिए पर्याप्त विश्वास नहीं है।

मैं इसे बाहर की कोशिश की है (जावा 1.6, ओएस एक्स) और पाया कि हाँ, वस्तुओं की पहचान क्रमबद्धता द्वारा अपरिवर्तित रहता है। लेकिन क्या मैं इन परिणामों से बाहर निकल सकता हूं या वे अविश्वसनीय हैं?

C----------+ 
| b1 b2 | 
+----------+ 
    |  | 
    v  v 
B---+ B---+ 
| a | | a | 
+---+ +---+ 
    \ /
    \/
    \/ 
    A----+ 
    | | 
    +----+ 

एक न्यूनतम reproducing कोड:

import java.io.*; 

public class SerializeTest { 
    static class A implements Serializable {} 

    static class B implements Serializable { 
     final A a; 

     public B(A a) { 
      this.a = a; 
     } 
    } 

    static class C implements Serializable { 
     final B b1, b2; 

     public C() { 
      A object = new A(); 
      b1 = b2 = new B(object); 
     } 
    } 

    public static void main(String[] args) throws IOException, 
      ClassNotFoundException { 
     C before = new C(); 
     System.out.print("Before: "); 
     System.out.println(before.b1.a == before.b2.a); 

     // Serialization. 
     ByteArrayOutputStream data = new ByteArrayOutputStream(); 
     ObjectOutputStream out = new ObjectOutputStream(data); 
     out.writeObject(before); 
     out.close(); 

     // Deserialization. 
     ObjectInputStream in = 
      new ObjectInputStream(new ByteArrayInputStream(data.toByteArray())); 
     C after = (C) in.readObject(); 
     System.out.print("After: "); 
     System.out.println(after.b1.a == after.b2.a); 
    } 
} 
+0

यदि यह एक == बी धारण करता है तो वे मनमानी वस्तुओं नहीं हैं। मेरा मानना ​​है कि आपका प्रश्न संदर्भों के लिए जाता है। –

उत्तर

18

दो मनमाना वस्तुओं ए और बी के लिए, यदि यह क्रमबद्धता से पहले एक == ख रखती है, यह अभी भी सच अक्रमांकन के बाद का आयोजन करेगा यदि:

  1. दोनों ए और बी के रूप में लिखा जाता है और बाद में हिस्से के रूप में से पढ़ एक ही धारा के।ObjectInputStream दस्तावेज से उद्धरण यहां दिया गया है: "संदर्भ साझाकरण तंत्र का उपयोग करके ऑब्जेक्ट्स के ग्राफ़ सही ढंग से बहाल किए जाते हैं।"
  2. ए और बी की कक्षा readResolve() को ओवरराइड नहीं करती है जिसमें संदर्भ बदलने की क्षमता है कि संदर्भ कैसे पुनर्स्थापित किए जाते हैं; न ही कक्षाएं जो एक और बी धारण करते हैं।

अन्य सभी मामलों के लिए, ऑब्जेक्ट पहचान संरक्षित नहीं की जाएगी।

+0

मुझसे बेहतर रखता है मुझे लगता है कि –

+2

ऑब्जेक्टऑटपुटस्ट्रीम क्लास के writeUnshared() विधि का उपयोग करने के परिणामों को आपके उत्तर में जोड़ना चाह सकता है। यह धारा पर नई अनूठी वस्तुओं को बनाने के समाप्त होता है। जावा ऑब्जेक्ट सीरियलाइजेशन स्पेसिफिकेशन पर http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf –

+0

पर अधिक जानकारी है धन्यवाद, यह वही है जो मैं ढूंढ रहा हूं। मेरे मामले में, मैं भाग्यशाली हूँ। यद्यपि 'ऑब्जेक्ट इनपुटप्रीम' दस्तावेज यहां अधिक स्पष्ट हो सकता है। परिभाषा के बिना, "संदर्भ साझाकरण" एक अपारदर्शी शब्द है। @ विनीट: चश्मा जोड़ने के लिए धन्यवाद। –

10

जवाब कोई है, डिफ़ॉल्ट वस्तु पहचान द्वारा संरक्षित नहीं है

अपने परीक्षण के लिए, मैं निम्नलिखित वस्तु ग्राफ धारावाहिक गए serialization के माध्यम से यदि आप किसी दिए गए ऑब्जेक्ट/ग्राफ़ के 2 अलग क्रमिकरणों पर विचार कर रहे हैं। उदाहरण के लिए, यदि मैं तार पर किसी ऑब्जेक्ट को क्रमबद्ध करता हूं (शायद मैं इसे क्लाइंट से आरएमआई के माध्यम से सर्वर पर भेजता हूं), और फिर इसे फिर से करें (अलग आरएमआई कॉल में), तो सर्वर पर 2 deserialized ऑब्जेक्ट्स नहीं होगा == हो।

हालांकि, "सिंगल सीरियलाइजेशन" उदा। एक एकल क्लाइंट-सर्वर संदेश जो एक ऑब्जेक्ट होता है जिसमें एक ही ऑब्जेक्ट होता है, फिर deserialization पर, पहचान संरक्षित है।

पहले मामले के लिए, आप, तथापि, readResolve विधि के एक कार्यान्वयन के क्रम में प्रदान कर सकते हैं यह सुनिश्चित करें कि सही उदाहरण दिया जाता है (typesafe enum पैटर्न में उदा)। readResolve एक निजी विधि है जिसे डी-सीरियलाइज्ड जावा ऑब्जेक्ट पर जेवीएम द्वारा बुलाया जाएगा, जिससे वस्तु को एक अलग उदाहरण वापस करने का मौका दिया जा सकेगा। उदाहरण के लिए, इस से पहले enum की भाषा में शामिल किया गया है कि कैसे TimeUnitenum लागू किया गया है हो सकता है:

public class TimeUnit extends Serializable { 

    private int id; 
    public TimeUnit(int i) { id = i; } 
    public static TimeUnit SECONDS = new TimeUnit(0); 

    //Implement method and return the relevant static Instance 
    private Object readResolve() throws ObjectStreamException { 
     if (id == 0) return SECONDS; 
     else return this; 
    } 
} 

+1

धन्यवाद। 'ReadResolve' का उपयोग करना वही है जो मैं टालना चाहता था क्योंकि मेरे मामले में टाइपफेफ एनम पैटर्न के मुकाबले बहीखाता अधिक जटिल हो जाएगी। मेरे लिए भाग्यशाली, मुझे केवल एकल क्रमबद्धता में रूचि है। –

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