【问题标题】:Why aren't my objects deserialized correctly?为什么我的对象没有正确反序列化?
【发布时间】:2011-05-18 21:49:44
【问题描述】:

我有一个非常简单的类层次结构:

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);
    }
}

当我创建一个新的 LongIdDropdownOption 实例时,确实实现了 Serializable;序列化它;然后立即反序列化它——然后反序列化对象的两个字段都设置为 null:

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 */
}

当我使基类实现 Serializable 时,代码开始正常工作。我的问题是……为什么?

【问题讨论】:

    标签: java serialization serializable deserialization


    【解决方案1】:

    如此处所述 - http://java.sun.com/developer/technicalArticles/ALT/serialization“重写 readObject 和 writeObject 的一个常见原因是为本身不可序列化的超类序列化数据”。​​

    您认为您在子类实例中的状态对于序列化并不真正可见,因为它不会通过您的 API 或反射进行。就序列化过程而言,状态属于不实现 Serializable 的超类。这就是你失去它的地方。

    这里有一个指向 Java 对象序列化规范的链接,应该对其进行解释: http://download.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html

    【讨论】:

      【解决方案2】:

      因为只有子类实现了Serializable,所以只有它的字段会被JVM序列化。 JVM 不会将父成员视为子类的成员,因为它使用反射来列出类的字段。

      【讨论】:

      • 谢谢,爱德华多,这是有道理的(有点)。这是否意味着基本上没有办法使子类可序列化,而不使其所有父类也可序列化?或者这仍然可以通过在子类中提供 readObject 和 writeObject 的自定义实现来实现吗?
      • 实际上,readObject 和 writeObject 方法应该只用于写入和恢复类的属性(参见bit.ly/eK2D9o)。如果你想序列化整个对象,我建议你实现 Externalizable 接口并提供方法 readExternal 和 writeExternal。
      【解决方案3】:

      来自 Java 文档Here

      如果A类没有实现Serializable,而B类实现了Serializable,那么B类的时候,A类的字段会被序列化吗?

      只有 Serializable 对象的字段被写出和恢复。仅当对象具有将初始化不可序列化超类型的字段的无参数构造函数时,才能恢复该对象。如果子类可以访问超类的状态,它可以实现 writeObject 和 readObject 来保存和恢复该状态。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多