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

时间:2013-04-26 14:45:21

标签: java serialization

当我阅读Serializable中有关Thinking in java界面的内容时,会出现一句话:

  

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

docs.oracle.com 5.6.2

  

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

所以,如果我不首先打电话给defaultWriteObject,如果我在打电话之前写了别的话,那会有问题吗?我试过了,但似乎它在我的例子中仍然有效。那么如果有任何问题,它会在什么条件下发生?

4 个答案:

答案 0 :(得分:4)

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

  

在编写相应ObjectOutputStream方法所需的任何可选数据之前,defaultWriteObject的{​​{1}}或writeFields方法必须被调用一次(并且只能调用一次)恢复对象的状态;即使没有写入可选数据,仍必须调用readObjectdefaultWriteObject一次。如果在编写可选数据(如果有)之前未调用writeFieldsdefaultWriteObject,则在{{1}的情况下,实例反序列化的行为为未定义无法解析定义所讨论的writeFields方法的类。

这是一个old thread,它给出了可能出现问题的示例。

这是一个JBoss AS Jira ticket和另一个例子。

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:1)

在Effective Java中描述:

  

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

答案 3 :(得分:0)

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

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