为什么在写入 ObjectOutputStream 时必须首先调用 defaultWriteObject 函数?

2022-09-03 07:35:32

当我在 中读到关于接口时,有一句话说:SerializableThinking in java

如果使用默认机制写入对象的非瞬态部分,则必须调用 defaultWriteObject( ) 作为 writeObject( ) 中的第一个操作,将 defaultReadObject( ) 作为 readObject( ) 中的第一个操作。

docs.oracle.com 5.6.2 中

添加 writeObject/readObject 方法 - 如果读取流的版本具有这些方法,则 readObject 应像往常一样读取通过默认序列化写入流的所需数据。在读取任何可选数据之前,它应该首先调用 defaultReadObject。与往常一样,writeObject 方法应调用 defaultWriteObject 来写入所需的数据,然后可以写入可选数据。

因此,如果我不先打电话,如果我在打电话之前写点别的东西,会有什么问题吗?我已经尝试过了,但似乎它在我的示例中仍然有效。那么,如果有什么问题,在什么条件下会发生呢?defaultWriteObject


答案 1

Java 对象序列化规范在这个主题上是模糊的:

在写入相应方法恢复对象状态所需的任何可选数据之前,必须调用一次(并且只能调用一次);即使没有写入任何可选数据,或者仍然必须调用一次。如果在写入可选数据(如果有)之前未调用或一次,则在 无法解析定义相关方法的类的情况下,实例反序列化的行为是未定义的ObjectOutputStreamdefaultWriteObjectwriteFieldsreadObjectdefaultWriteObjectwriteFieldsdefaultWriteObjectwriteFieldsObjectInputStreamwriteObject

这是一个旧线程,它给出了一个可能发生问题的示例案例。

这是一张JBoss AS Jira票证,上面有另一个例子。


答案 2

它在 Effective Java 中进行了描述:

如果所有实例字段都是瞬态的,则在技术上允许免除调用 defaultWriteObject 和 defaultReadObject ,但不建议这样做。即使所有实例字段都是瞬态的,调用 defaultWriteObject 也会影响序列化表单,从而大大增强灵活性。生成的序列化形式使得在以后的版本中添加非瞬态实例字段成为可能,同时保持向后和向前兼容性。如果实例在更高版本中序列化,而在早期版本中反序列化,则将忽略添加的字段。如果早期版本的 readObject 方法无法调用 defaultReadObject,则反序列化将失败,并显示 StreamCorruptedException 。