【问题标题】:Implementing Serializable without providing writeObject / readObject method在不提供 writeObject / readObject 方法的情况下实现 Serializable
【发布时间】:2016-03-27 06:02:34
【问题描述】:

如果一个类实现了可序列化接口,但代码库中没有writeObject/readObject 方法实现怎么办?

默认方法defaultWriteObject/defaultReadObject 是否会进行序列化?

仅用implements Serializable 标记类就足以序列化一个类吗?

如果是,那么什么被序列化了,对象的状态在哪里被持久化?

【问题讨论】:

标签: java serializable


【解决方案1】:

如果一个类正在实现可序列化的接口,但代码库中的任何地方都没有 writeObject/readObject 方法实现怎么办?

它将受到默认序列化:见下文。

默认方法defaultWriteObject/defaultReadObject会不会进行序列化?

不,因为除非您调用它们,否则它们不会被调用。

仅用implements Serializable 标记类是否足以序列化一个类?

是的,如果您对默认序列化感到满意:见下文。

如果是,那么正在序列化什么

类的所有非瞬态非静态成员变量及其实现Serializable,的所有基类,仅此而已。

对象的状态在哪里被持久化?

进入溪流。你的这部分问题似乎没有意义,

【讨论】:

  • 谢谢。对于最后一部分,如果我没有在任何地方调用 writeObject/readObject 来实际序列化或持久化对象的状态,甚至不提供通过 FileOutputStream 持久化数据的文件名。
  • @MooG 如果您不调用执行序列化的方法,那么您就没有执行序列化。提供文件名也与它无关。仍然无法理解您的观点。
【解决方案2】:

1)默认方法defaultWriteObject/defaultReadObject是否会进行序列化? -不,

defaultReadObject() 调用默认的反序列化机制,在定义 readObject() 方法时使用 在您的 Serializable 类上。换句话说,当您有自定义反序列化逻辑时, 您仍然可以返回默认序列化,这将反序列化您的非静态、非瞬态字段。 例如:

public class TestClass implements Serializable {
    private String f2;
    private int f1;
    private transient String f3; 
    private void readObject(java.io.ObjectInputStream stream)
         throws IOException, ClassNotFoundException {
         stream.defaultReadObject(); //fills f1 and f2;
         fld3 = Configuration.getFooConfigValue();
    }
}

另一方面,从反序列化对象外部创建 ObjectInputStream 时使用 readObject(), 并想读取之前序列化的对象:

ObojectInputStream stream = new ObjectInputStream(aStreamWithASerializedObject);
Object foo = (Foo) stream.readObject();

java.io.ObjectOutputStream.defaultWriteObject() 方法将当前类的非静态和非瞬态字段写入此流。这只能从被序列化的类的 writeObject 方法调用 此方法允许完全控制将通过线路发送的内容。 在大多数情况下,您只需调用 out.defaultWriteObject() 即可从默认序列化过程中受益。

2)仅使用实现 Serializable 的类来标记类就足以序列化一个类吗? 是的,

只要几行代码,任何其类实现 java.io.Serializable 接口的对象都可以持久化。 不需要添加额外的方法来实现接口, 然而 - 接口的目的是在运行时识别哪些类可以安全地序列化, 哪个不能。您只需将 implements 关键字添加到您的类声明中,即可将您的类标识为可序列化的。

现在,一旦类可序列化,我们就可以将对象写入任何 OutputStream,例如磁盘或套接字连接。 要实现这一点,我们必须首先创建java.io.ObjectOutputStream, 的实例 并将现有的 OutputStream 实例传递给构造函数。

/ Write to disk with FileOutputStream
FileOutputStream f_out = new 
    FileOutputStream("myobject.data");

// Write object with ObjectOutputStream
ObjectOutputStream obj_out = new
    ObjectOutputStream (f_out);



 // Write object out to disk
    obj_out.writeObject ( myObject );

3)如果是,那么什么被序列化了,对象的状态在哪里被持久化? 该类的所有非瞬态非静态成员变量及其所有实现 Serializable 的基类都将以某些 media/file.object 的状态持久化到持久性存储中,并在将来需要时从保存的信息中重建对象.

【讨论】:

  • 谢谢。一个快速查询。如果我不编写那些额外的代码行来指定将通过 FileOutputStream 或 writeObject/readObject 方法调用保持状态的文件名。
【解决方案3】:

https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

这也是一个很好的文档,可以参考理解您要求的该文档的 sn-p 点,这可以帮助您更多地理解它。

writeObject 方法负责为其特定类写入对象的状态,以便相应的 readObject 方法可以恢复它。可以通过调用 out.defaultWriteObject 来调用保存 Object 字段的默认机制。该方法不需要关注属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存状态。

readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来调用用于恢复对象的非静态和非瞬态字段的默认机制。 defaultReadObject 方法使用流中的信息将保存在流中的对象的字段分配给当前对象中相应命名的字段。这可以处理类已演变为添加新字段的情况。该方法不需要关注属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存状态。

如果序列化流未将给定类列为被反序列化对象的超类,readObjectNoData 方法负责为其特定类初始化对象的状态。这可能发生在接收方使用与发送方不同版本的反序列化实例类的情况下,并且接收方的版本扩展了发送方版本未扩展的类。如果序列化流被篡改,也可能发生这种情况;因此,尽管存在“敌对”或不完整的源流,但 readObjectNoData 对于正确初始化反序列化对象很有用。

【讨论】:

  • 我最近一直在阅读这个主题,但不幸的是,这个文档没有回答我的问题。无论如何,感谢您的快速响应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
相关资源
最近更新 更多