我怎么能不序列化继承的非瞬态字段?

时间:2013-07-30 08:14:37

标签: java serialization

问题

我有一个Serializable类(我们称之为A),它带有一个非瞬态布尔字段,以及一个子类(B),该字段应该是瞬态的。我怎么能这样做?

更确切地说,我希望在反序列化B时将字段恢复为默认的布尔值(false),尽管我希望在反序列化时将其恢复为正确的值。其他字段继承自A应该恢复。

功能上,A表示在会话之间恢复的对象,B是特定类型的A,其状态应在每个新会话中重置。

快速代码示例:

public class A implements java.io.Serializable {

    private String label;
    // non-transient
    private boolean field;

    public String getLabel() {
        return label;
    }

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

    public boolean isField() {
        return field;
    }

    public void setField(boolean field) {
        this.field = field;
    }
}

public class B extends A {
    // field should be transient for this class
    // label should remain non-transient
}

我选择不保留的一些可能的解决方案

  • 一个简单的解决方案是将B extends A更改为A extends B,使字段成为瞬态,并向A添加writeObject()以序列化字段。但是,B extends A具有功能意义,我不相信还原它是明智的。

  • 我可以实现一个readObject()方法,该方法会覆盖该字段的反序列化值。然而,这感觉就像一个肮脏的解决方案,除非别无选择,否则我不想使用它。

  • 我尝试编写一个writeObject()方法来模拟瞬态字段,但它不起作用,我不知道为什么。如果有人有线索,那可能是我的解决方案:

public class B extends A {
    private void writeObject(ObjectOutputStream out) throws IOException {
        // save current state
        boolean field = isField();

        // synchronized to make sure this instance is not interrogated
        // while changed for serialization
        synchronized (this) {
            // emulate transient state and serialize
            setField(false);
            out.defaultWriteObject();

            // restore state
            setField(field);
        }
    }
}
  • 编辑:@ rocketboy使用阴影效果的解决方案,但我对阴影感到不舒服,因为它会留下一个未使用的字段(A的非瞬态字段永远不会被使用,而B的瞬态版本将被写入和读取)。这可能是一个解决方案。做实验的Java开发人员认为这是一个干净的解决方案吗?
public class B extends A {
    // shadow A's field
    private transient boolean field;

    @Override
    public boolean getField() {
        return field;
    }

    @Override
    public void setField(boolean field) {
        this.field = field;
    }
}

答案

按照@ m1o2的建议,我已经能够使用Externalizable界面实现我的解决方案:

public class B extends A implements java.io.Externalizable {

    // Do not forget to have a public no-arg constructor
    // for Serialization to work
    public B() {
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        // Write only the fields I am interested in
        out.writeObject(getLabel());
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        // Read the serialized fields IN THE ORDER THEY WERE WRITTEN
        setLabel((String) in.readObject());
    }
}

但请注意,这是适用的,因为A和B是简单的类。对于具有许多字段且有进化趋势的类,这可能会花费更多(除非使用基于反射的某些代码)。

1 个答案:

答案 0 :(得分:1)

如果您不关心Superclass字段(所有字段),可以使用Externalizable interface