2010-12-02 13 views
2

私はかなり単純なクラス階層を持っている:なぜオブジェクトが正しくデシリアライズされていないのですか?

public class DropdownOption<T> /* does NOT implement Serializable */ { 
    private T value; 
    private String label; 

    public DropdownOption() { 
     this (null, null); 
    } 

    public DropdownOption(T value, String label) { 
     this.value = value; 
     this.label = label; 
    } 

    public T getValue() { 
     return value; 
    } 

    public void setValue(T value) { 
     this.value = value; 
    } 

    public String getLabel() { 
     return label; 
    } 

    public void setLabel(String label) { 
     this.label = label; 
    } 
} 

/** 
* Convenience decorator 
*/ 
public class LongIdDropdownOption extends DropdownOption<Long> 
    implements Serializable { 

    private static final long serialVersionUID = -3920989081132516015L; 

    public LongIdDropdownOption() { 
     super();   
    } 

    public LongIdDropdownOption(Long value, String label) { 
     super(value, label); 
    } 

    public Long getId() { 
     return getValue(); 
    } 

    public void setId(Long id) { 
     super.setValue(id); 
    } 
} 

私ははSerializableを実装していLongIdDropdownOption、の新しいインスタンスを作成すると、それを直列化する。その後、すぐにそれをデシリアライズ - その後、非直列化されたオブジェクトがnullに設定されたフィールドの両方を持っている:私は、基本クラスがSerializableを実装作るとき

public void testSerialization() throws Exception { 
    LongIdDropdownOption option = new LongIdDropdownOption(1L, "One");   

    ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
    ObjectOutputStream os = new ObjectOutputStream(buffer); 
    os.writeObject(option); 
    os.close(); 

    ObjectInputStream is = new ObjectInputStream(
     new ByteArrayInputStream(buffer.toByteArray())); 
    LongIdDropdownOption result = (LongIdDropdownOption) is.readObject(); 
    is.close(); 

    assertNotNull(result);   
    assertEquals("One", result.getLabel()); /** Fails, label is null */ 
} 

、コードが正しく動作開始します。私の質問は...なぜ?

答えて

4

ここで説明したように - http://java.sun.com/developer/technicalArticles/ALT/serialization "readObjectとwriteObjectをオーバーライドする一般的な理由の1つは、Serializable自体ではないスーパークラスのデータをシリアル化することです。"

あなたのサブクラス化されたインスタンスにあると思われる状態は、APIまたはリフレクションを経由しないため、シリアライゼーションには実際には見えません。シリアライゼーションプロセスに関しては、状態はシリアライズ可能ではないスーパークラスに属します。これはあなたがそれを失う場所です。ここで

はそれを説明する必要があるJavaオブジェクト直列化仕様へのリンクです:(ソートの)理にかなって http://download.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html

4

子クラスのみがSerializableを実装するため、そのフィールドだけがJVMによってシリアル化されるためです。 JVMは、リフレクションを使用してクラスのフィールドをリストするので、親クラスのメンバーを子クラスのメンバーとして認識しません。

+0

おかげで、エドゥアルド、。基本的に、すべての親クラスをSerializableにすることなく、子クラスをSerializableにする方法はないのでしょうか?これは、子クラスにreadObjectとwriteObjectのカスタム実装を提供することで可能ですか? – Bugmaster

+0

実際、readObjectメソッドとwriteObjectメソッドは、クラスの属性の書き込みと復元にのみ使用する必要があります(http://bit.ly/eK2D9oを参照)。オブジェクト全体を直列化したい場合は、Externalizableインターフェイスを実装し、readExternalメソッドとwriteExternalメソッドを提供することをお勧めします。 – EdMelo

3

HereのJavaドキュメントからクラスAがSerializableを実装していませんが、サブクラスBがSerializableを実装した場合Bがシリアライズされたときに、クラスAのフィールドは直列化されたのだろうか?

Serializableオブジェクトのフィールドのみが書き出され、復元されます。オブジェクトは、直列化不可能なスーパータイプのフィールドを初期化する引数なしコンストラクタがある場合にのみリストアできます。サブクラスがスーパークラスの状態にアクセスできる場合、サブクラスはwriteObjectおよびreadObjectを実装して、その状態を保存および復元できます。

関連する問題