具有不可序列化部件的 Java 序列化

2022-08-31 20:04:16

我有:

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

在 MyClass2 中,是一个不可序列化的属性。如何序列化(和反序列化)此对象?

更正:当然,MyClass2 不是一个接口,而是一个类。


答案 1

正如其他人所指出的,Josh Bloch的《Effective Java》第11章是关于Java序列化的不可或缺的资源。

该章中与您的问题相关的几点:

  • 假设您要序列化 MyClass2 中不可序列化字段的状态,则 MyClass 必须可以直接或通过 getter 和 setter 访问该字段。MyClass 必须通过提供 readObject 和 writeObject 方法来实现自定义序列化。
  • 不可序列化字段的类必须具有 API,以允许获取其状态(用于写入对象流),然后实例化具有该状态的新实例(稍后从对象流读取时)。
  • 根据 Effective Java 的第 74 项,MyClass2 必须具有可访问的无 arg 构造函数,否则 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;
  }
}

答案 2

MyClass2只是一个技术性很强的接口,它没有属性,只有方法。话虽如此,如果你有实例变量本身不可序列化,我知道的解决它的唯一方法是将这些字段声明为瞬态。

前任:

private transient Foo foo;

当您声明字段瞬态时,在序列化和反序列化过程中将忽略该字段。请记住,当您使用瞬态字段反序列化对象时,该字段的值将始终为默认值(通常为 null)。

注意 您还可以重写类的 readResolve() 方法,以便基于其他系统状态初始化瞬态字段。