我有一个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);
}
}
}
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是简单的类。对于具有许多字段且有进化趋势的类,这可能会花费更多(除非使用基于反射的某些代码)。