16

当我读到关于Serializable接口的Thinking in java时候,有一句话说:

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

docs.oracle.com 5.6.2中:

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

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

4

4 回答 4

6

Java 对象序列化规范在这个主题上含糊不清:

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

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

这是另一个示例的 JBoss AS Jira 票证

于 2013-04-26T15:09:37.477 回答
3

它在 Effective Java 中有描述:

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

于 2015-08-01T12:53:11.333 回答
2

我认为文档中的关键词是“应该”,这意味着您不必这样做。

我认为这比其他任何事情都更像是一种最佳实践。如果我第一次阅读您的代码并看到您在第一行默认了读/写,我可以对自己说“好的,完成了 90% 的课程”,然后专注于您的自定义代码所有非瞬态,非静态实例变量..

最重要的是以相同的顺序读/写。除此之外,您可以自由地为所欲为。

于 2013-04-26T15:11:05.973 回答
0

我认为那是因为你知道你在双方都做了什么,并且在相反的情况下做“相同”或更好......

但是:如果其他程序员会在不知道您不使用默认值的情况下针对您的序列化编写反序列化,他可能使用推荐的 defaultReadObject,然后遇到奇怪的异常。

于 2013-04-26T15:11:27.200 回答