2008-09-18 90 views
51

我:Java序列與非序列化部分

class MyClass extends MyClass2 implements Serializable { 
    //... 
} 

在MyClass2是不可序列化的屬性。我怎樣才能序列化(和反序列化)這個對象?

更正:MyClass2當然不是一個接口,而是一個類。

+0

可以修改MyClass2與否:

下面是一個例子,如何使用KRYO

Kryo kryo = new Kryo(); // #### Store to disk... Output output = new Output(new FileOutputStream("file.bin")); SomeClass someObject = ... kryo.writeObject(output, someObject); output.close(); // ### Restore from disk... Input input = new Input(new FileInputStream("file.bin")); SomeClass someObject = kryo.readObject(input, SomeClass.class); input.close(); 

序列化對象可以通過註冊一個確切的串行器也被壓縮?是否需要通過序列化來保留不可序列化的屬性值? 正確的方法取決於此。 – erickson 2008-09-18 18:30:29

+0

MyClass2可以修改。但是,最好不要,因爲我建立在它之上,並且可以被其他人修改。 – Burkhard 2008-09-19 11:04:41

回答

49

正如其他人指出的,Josh Bloch的Effective Java的第11章是Java序列化中不可或缺的資源。

從章有關你的問題有幾點:

  • 假設你想要序列中MyClass2非序列化字段的狀態,那場必須能夠訪問到MyClass的,直接或通過干將和制定者。 MyClass必須通過提供readObject和writeObject方法來實現自定義序列化。
  • 不可序列化字段的Class必須具有一個API以允許獲取它的狀態(用於寫入對象流),然後使用該狀態實例化一個新實例(當從對象流中讀取後)。
  • per Item有效Java的74,MyClass2 必須有一個無參數構造函數可以訪問MyClass,否則MyClass不可能擴展MyClass2並實現Serializable。

我已經寫了一個快速示例來說明這一點。


class MyClass extends MyClass2 implements Serializable{ 

    public MyClass(int quantity) { 
    setNonSerializableProperty(new NonSerializableClass(quantity)); 
    } 

    private void writeObject(java.io.ObjectOutputStream out) 
    throws IOException{ 
    // note, here we don't need out.defaultWriteObject(); because 
    // MyClass has no other state to serialize 
    out.writeInt(super.getNonSerializableProperty().getQuantity()); 
    } 

    private void readObject(java.io.ObjectInputStream in) 
    throws IOException { 
    // note, here we don't need in.defaultReadObject(); 
    // because MyClass has no other state to deserialize 
    super.setNonSerializableProperty(new NonSerializableClass(in.readInt())); 
    } 
} 

/* this class must have no-arg constructor accessible to MyClass */ 
class MyClass2 { 

    /* this property must be gettable/settable by MyClass. It cannot be final, therefore. */ 
    private NonSerializableClass nonSerializableProperty; 

    public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) { 
    this.nonSerializableProperty = nonSerializableProperty; 
    } 

    public NonSerializableClass getNonSerializableProperty() { 
    return nonSerializableProperty; 
    } 
} 

class NonSerializableClass{ 

    private final int quantity; 

    public NonSerializableClass(int quantity){ 
    this.quantity = quantity; 
    } 

    public int getQuantity() { 
    return quantity; 
    } 
} 
33

MyClass2只是一個界面,所以它沒有任何屬性,只有方法。這就是說,如果你有實例變量本身不可序列化,我知道解決它的唯一方法是聲明這些字段是瞬態的。

例如:

private transient Foo foo; 

在聲明場瞬時將在序列化和反序列化過程中被忽略。請記住,當使用瞬態字段反序列化對象時,該字段的值始終爲缺省值(通常爲空)。

請注意,您也可以重寫類的readResolve()方法,以基於在其他系統狀態。

6

您將需要執行writeObject()readObject()並對這些字段進行手動序列化/反序列化。有關詳細信息,請參閱java.io.Serializable的javadoc頁面。 Josh Bloch的Effective Java在實現健壯和安全的序列化方面也有一些很好的章節。

4

您可以通過查看瞬態關鍵字開始,該關鍵字將字段標記爲不是對象持久狀態的一部分。

11

如果您可以修改MyClass2,解決此問題的最簡單方法是聲明屬性瞬態。

+0

這不回答問題 - 問題狀態MyClass2包含不可序列化的屬性,理想情況下不應修改MyClass2。 – 2012-09-07 18:20:24

+0

你說得對,當我回答時,我沒有仔細閱讀過這個問題。我修改了答案。 – ykaganovich 2012-09-07 18:46:30

3

XStream是一個偉大的庫,用於爲任何對象執行快速的Java到XML序列化,而不管它是否可序列化。即使XML目標格式不適合您,您也可以使用源代碼來學習如何執行此操作。

5

取決於MyClass2的成員不可序列化的原因。

如果說MyClass2不能用序列化的形式表示,那麼很可能是同樣的原因適用於MyClass,因爲它是一個子類。

通過實現readObject和writeObject,可以爲MyClass編寫自定義序列化表單,從而可以從序列化數據中適當地重新創建MyClass中的MyClass2實例數據的狀態。如果MyClass2的API已修復並且您無法添加Serializable,那麼這將是一條路。

但首先你應該弄清楚爲什麼MyClass2不可序列化,並且可能改變它。

2

用於串行化不可序列類的實例的有用方法(或在至少子類)是已知的串行代理。從本質上講,你實現了writeReplace來返回一個完全不同的可序列化的類的實例,它實現了readResolve來返回原始對象的副本。我寫了一篇關於Usenet

4

幾種可能性連載java.awt.BasicStroke中的一個例子POP操作了,我在這裏繼續他們:

  • 實現的writeObject()和readObject()作爲sk建議
  • 申報財產瞬態和如通過boris-terzic
  • 表示使用串行代理通過說,它不會被序列化爲第一通過hank
  • 使用XStream的說
15

如果可能的話,非serialiable部分可以設置爲瞬時

private transient SomeClass myClz; 

否則,你可以使用Kryo。 Kryo是用於Java的快速高效的對象圖形序列化框架(例如java.awt.Color的JAVA序列化需要170個字節,Kryo只有4個字節),它還可以序列化非可序列化的對象。 Kryo還可以執行自動深層和淺層複製/克隆。這是直接從對象複製到對象,而不是object->bytes->object

kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));