0

假设我有一个ArrayList<B> array来自某个类的对象B,它扩展了AB有一个实例字段bbA一个字段aa。我知道使用保存array到 .dat 文件ObjectOutputStream需要B(不仅仅是ArrayList!)实现Serializable。但是,我发现从文件中加载对象时(使用ObjectInputStream):

 arrayLoaded = (ArrayList<B>)myObjIn.readObject();

加载的数组与原始数组不同:在特定情况下,arrayLoaded.get(0).bb具有与 in 相同的值array,但arrayLoaded.get(0).aa被“归零”。它有一个默认的初始化值,不管它在array保存到文件时的值。但是,这个问题可以通过让也A实现来解决Serializable

困扰我的是这个错误是如此微妙:没有例外,没有警告(在 Eclipse 中),什么都没有。这是有原因的还是仅仅是Java开发人员的疏忽?Serializable每次我想使用对象 IO 流时,我是否只需要接受它并认真考虑层次结构中的哪些类实现?

4

2 回答 2

2

仅仅因为Bimplements Serializable,它不会追溯性地将不可序列化超类的字段包含在被序列化的内容中。(这是有道理的,特别是当您认为能够仅通过扩展和实现任何类的私有和包私有字段来序列化它Serializable会违反其封装。)

在中声明的字段的行为与在A中声明的字段相同。然而,有一个解决方法。从文档中:transientBSerializable

为了允许序列化不可序列化类的子类型,子类型可以负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态。仅当它扩展的类具有可访问的无参数构造函数来初始化类的状态时,子类型才可以承担此责任。

因此,您将需要实现writeObject并处理readObject.BA.aa

于 2013-01-20T01:47:13.810 回答
2

困扰我的是这个错误是如此微妙:没有例外,没有警告(在 Eclipse 中),什么都没有。这是有原因的还是仅仅是Java开发人员的疏忽?

这是设计使然。(见@Paul Bellora 的回答)。替代方案是:

  • 声明一个类 Serializable 是非法的,除非它的超类是 Serializable。这显然是行不通的。

  • 如果应该或不能序列化,自动序列化中断的超类字段。(请注意,我们不能依赖transient这里,因为如果超类的设计者不打算将其序列化,他/她将不会标记这些字段。)

每次我想使用对象 IO 流时,我是否只需要接受它并认真考虑层次结构中的哪些类实现了 Serializable ?

基本上,是的。特别是,当您编写现有非可序列化类的可序列化子类时,您需要认真思考。

我想可以编写 FindBugs / PMD / etc 规则来将此特定用法标记为潜在问题。

于 2013-01-20T03:22:32.663 回答