反序列化对象时是否忽略意外字段?

时间:2015-03-10 11:19:21

标签: java serialization

来自文档:

http://docs.oracle.com/javase/8/docs/platform/serialization/spec/version.html#a5172

  

对类的不兼容更改是对其进行的更改    无法保证互操作性 。不相容   在进化课程时可能发生的变化是:

     

删除字段 - 如果在类中删除某个字段,则会写入该流   不会包含它的价值。当流被早先读取时   class,该字段的值将被设置为默认值,因为   流中没有可用的值。但是,此默认值可能   不利地削弱了早期版本实现其能力   合同。

     

等...

此处,使用"删除字段"作为一种不相容的变化意味着:

例如可序列化的类A:

public class A implements Serializable {
    private static final long serialVersionUID = -13921739827197L;

    private B fieldB;
    private C fieldC;
    // ... getters and setters for both fields
}

如果我现在序列化这个类, fieldB fieldC 将被序列化(当然B和C也实现Serializable)。

现在,如果我从A类中删除 fieldB

public class A implements Serializable {
    private static final long serialVersionUID = -13921739827197L;

    private C fieldC;
    // ... getter and setter only for fieldC
}

如果我现在尝试序列化这个类的实例,只会将fieldC序列化,因为不再有fieldB。

如果现在我将此序列化传递给使用以前版本的A类的JVM实例(因此使用 fieldB fieldC 的那个),作为seriliazed对象类 A 的序列化中没有 fieldB ,结果将是 A 类的旧版本的实例< em> fieldB 设置为null(默认值,就像&#34;添加字段&#34;兼容更改)。当然这可能导致&#34; null&#34;指针异常和意外结果,这就是为什么Oracle说它应该被认为是一个&#34;不兼容的变化&#34;。

然而,如果相反的情况会发生什么呢?

例如,如果发生旧版A类(包含 fieldB fieldC )的deserialization实例并且JVM具有A类的较新版本(因此,没有 fieldB )?

序列化API如何处理这个问题?它会简单地丢弃 fieldB 吗?

2 个答案:

答案 0 :(得分:3)

规范在这一点上具有误导性。

从序列化本身的角度来看,删除是兼容的:也就是说,它不会触发IncompatibleClassChangeException.规范试图传达的是应用程序可能经历不相容。

但它不应该在规范中的“不兼容的变化”下列出:从序列化的角度来看,它是与字段插入或重新排序完全相同的变化:兼容的变化。

也就是说,最后并且实际上回答了你的问题,流中的多余字段将被简单地丢弃。

答案 1 :(得分:1)

您正在阅读的相同规范有答案:

  

3.1 The ObjectInputStream Class

     

...

     

将丢弃流中出现但未在对象中出现的类的数据。对于在对象中出现但在流中不出现的类,类字段设置为默认值为默认值序列化。