反序列化对象时是否会忽略意外字段?
Are unexpected fields ignored when deserializing an object?
来自文档:
http://docs.oracle.com/javase/8/docs/platform/serialization/spec/version.html#a5172
Incompatible changes to classes are those changes for which the
guarantee of interoperability cannot be maintained. The incompatible
changes that may occur while evolving a class are:
Deleting fields - If a field is deleted in a class, the stream written
will not contain its value. When the stream is read by an earlier
class, the value of the field will be set to the default value because
no value is available in the stream. However, this default value may
adversely impair the ability of the earlier version to fulfill its
contract.
etc...
这里,以"deleting fields"作为不兼容的变化意味着:
有例如一个可序列化的 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
}
如果我现在序列化这个class,fieldB和fieldC都会被序列化(当然B和C也会实现可序列化)。
现在,如果我从 class A 中删除 fieldB:
public class A implements Serializable {
private static final long serialVersionUID = -13921739827197L;
private C fieldC;
// ... getter and setter only for fieldC
}
如果我现在尝试序列化此 class 的一个实例,将仅序列化 fieldC,因为不再有 fieldB。
如果我现在将此序列化传递给一个 JVM 实例,其中使用了 class A 的先前版本(因此具有 fieldB 和 fieldC),因为 class A 的序列化对象在其序列化中没有 fieldB,结果将是旧版本 class A 的实例,其中 fieldB 设置为 null
(默认值,就像当 "Adding fields" 兼容更改时)。当然这可能会导致 "null" 指针异常和意想不到的结果,这就是为什么 Oracle 说它应该被认为是一个 "incompatible change".
但是,如果出现相反的情况怎么办?
例如,如果 class A 的旧版本实例的 deserialization
会怎样(都带有 fieldB 和 fieldC) 发生并且 JVM 有更新版本的 class A(因此,没有 fieldB)?
序列化 API 将如何处理这个问题?它会简单地丢弃fieldB吗?
规范在这一点上具有误导性。
删除从序列化本身的角度来看是兼容的:也就是说,它不会触发IncompatibleClassChangeException.
规范试图传达的是应用程序 可能会遇到不兼容问题。
但它不应列在规范中的 'incompatible changes' 下:从序列化的角度来看,它是与字段插入或重新排序性质完全相同的更改:兼容的更改。
也就是说,为了最终真正回答您的问题,流中多余的字段将被简单地丢弃。
您正在阅读的同一规范有答案:
3.1 The ObjectInputStream Class
...
Data for classes that occur in the stream, but do not occur in the object, is discarded. For classes that occur in the object, but not in the stream, the class fields are set to default values by default serialization.
来自文档:
http://docs.oracle.com/javase/8/docs/platform/serialization/spec/version.html#a5172
Incompatible changes to classes are those changes for which the guarantee of interoperability cannot be maintained. The incompatible changes that may occur while evolving a class are:
Deleting fields - If a field is deleted in a class, the stream written will not contain its value. When the stream is read by an earlier class, the value of the field will be set to the default value because no value is available in the stream. However, this default value may adversely impair the ability of the earlier version to fulfill its contract.
etc...
这里,以"deleting fields"作为不兼容的变化意味着:
有例如一个可序列化的 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
}
如果我现在序列化这个class,fieldB和fieldC都会被序列化(当然B和C也会实现可序列化)。
现在,如果我从 class A 中删除 fieldB:
public class A implements Serializable {
private static final long serialVersionUID = -13921739827197L;
private C fieldC;
// ... getter and setter only for fieldC
}
如果我现在尝试序列化此 class 的一个实例,将仅序列化 fieldC,因为不再有 fieldB。
如果我现在将此序列化传递给一个 JVM 实例,其中使用了 class A 的先前版本(因此具有 fieldB 和 fieldC),因为 class A 的序列化对象在其序列化中没有 fieldB,结果将是旧版本 class A 的实例,其中 fieldB 设置为 null
(默认值,就像当 "Adding fields" 兼容更改时)。当然这可能会导致 "null" 指针异常和意想不到的结果,这就是为什么 Oracle 说它应该被认为是一个 "incompatible change".
但是,如果出现相反的情况怎么办?
例如,如果 class A 的旧版本实例的 deserialization
会怎样(都带有 fieldB 和 fieldC) 发生并且 JVM 有更新版本的 class A(因此,没有 fieldB)?
序列化 API 将如何处理这个问题?它会简单地丢弃fieldB吗?
规范在这一点上具有误导性。
删除从序列化本身的角度来看是兼容的:也就是说,它不会触发IncompatibleClassChangeException.
规范试图传达的是应用程序 可能会遇到不兼容问题。
但它不应列在规范中的 'incompatible changes' 下:从序列化的角度来看,它是与字段插入或重新排序性质完全相同的更改:兼容的更改。
也就是说,为了最终真正回答您的问题,流中多余的字段将被简单地丢弃。
您正在阅读的同一规范有答案:
3.1 The ObjectInputStream Class
...
Data for classes that occur in the stream, but do not occur in the object, is discarded. For classes that occur in the object, but not in the stream, the class fields are set to default values by default serialization.