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

当我Thinking in java阅读Thinking in javaSerializable接口时,有一句话说:

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

在docs.oracle.com 5.6.2中 :

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

所以,如果我不首先调用defaultWriteObject ,并且如果我在该调用之前写了其他内容,那么会有任何问题吗? 我试过了,但似乎它在我的例子中仍然运作良好。 那么如果有任何问题,它会在什么条件下发生?

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

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

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

这是另一个例子的JBoss AS Jira票 。

我认为文档中的关键词是“应该” ,这意味着你没有必要。

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

最重要的是以相同的顺序读/写 。 除此之外,你可以自由地做你喜欢的事。

它在Effective Java中描述:

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

我认为这是因为你知道你在双方所做的事情并且做出相同的“相同”或更好的相反……

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