我序列化一个对象并通过网络进行传输。我序列化的类对象具有我定义的自己的serilizableId。现在在另一个JVM中,我保持SeriliazibleId不变,但是更改了一些属性。
将会发生什么,为什么?它将能够反序列化吗?
最佳答案
您必须参考Java对象序列化规范here。
具体而言,您不得执行以下操作:
删除字段-如果在类中删除了字段,则写入的流将不包含其值。当较早的类读取流时,该字段的值将设置为默认值,因为流中没有可用的值。但是,此默认值可能会不利地损害早期版本履行其合同的能力。
将类上移或下移-这是不允许的,因为流中的数据以错误的顺序显示。
将非静态字段更改为静态或将非瞬态字段更改为瞬态-当依赖默认序列化时,此更改等效于从类中删除字段。该版本的类不会将该数据写入流,因此该类的早期版本将无法读取该数据。与删除字段时一样,早期版本的字段将被初始化为默认值,这可能导致类以意外方式失败。
更改原始字段的声明类型-类的每个版本都使用其声明类型写入数据。尝试读取该字段的早期版本的类将失败,因为流中的数据类型与该字段的类型不匹配。
更改writeObject或readObject方法,使其不再写入或读取默认字段数据,或者对其进行更改,以使其尝试写入或读取默认字段数据,而先前版本则不这样做。默认字段数据必须一致地出现在流中或不出现在流中。
将类从Serializable更改为Externalizable或将其更改为Externalizable都是不兼容的更改,因为流将包含与可用类的实现不兼容的数据。
将类从非枚举类型更改为枚举类型,反之亦然,因为流将包含与可用类的实现不兼容的数据。
删除Serializable或Externalizable是一项不兼容的更改,因为在编写时它将不再提供该类的旧版本所需的字段。
如果该行为会产生与该类的任何旧版本不兼容的对象,则将writeReplace或readResolve方法添加到类是不兼容的。
您可以执行以下操作:
添加字段-当要重构的类的字段在流中不存在时,该对象中的该字段将被初始化为其类型的默认值。如果需要特定于类的初始化,则该类可以提供一个readObject方法,该方法可以将字段初始化为非默认值。
添加类-流将包含流中每个对象的类型层次结构。将流中的此层次结构与当前类进行比较可以检测到其他类。由于流中没有用于初始化对象的信息,因此该类的字段将被初始化为默认值。
删除类-将流中的类层次结构与当前类的层次结构进行比较可以检测到某个类已被删除。在这种情况下,从该流中读取与该类相对应的字段和对象。原始字段将被丢弃,但是会创建由删除的类引用的对象,因为它们可能稍后在流中被引用。当流被垃圾回收或重置时,它们将被垃圾回收。
添加writeObject / readObject方法-如果读取流的版本具有这些方法,则通常希望readObject读取通过默认序列化写入流中的所需数据。在读取任何可选数据之前,应先调用defaultReadObject。通常,writeObject方法将调用defaultWriteObject写入所需的数据,然后再写入可选数据。
删除writeObject / readObject方法-如果读取流的类没有这些方法,则默认情况下将序列化读取所需的数据,并将丢弃可选数据。
添加java.io.Serializable-这等同于添加类型。该类的流中将没有任何值,因此其字段将被初始化为默认值。对子类化不可序列化类的支持要求该类的超类型具有no-arg构造函数,并且该类本身将被初始化为默认值。如果no-arg构造函数不可用,则抛出InvalidClassException。
更改对字段的访问权限-访问修饰符public,package,protected和private对序列化为字段分配值的能力没有影响。
将字段从静态更改为非静态,或将瞬态更改为非瞬态-当依赖默认序列化来计算可序列化字段时,此更改等效于将字段添加到类中。新字段将被写入流,但是较早的类将忽略该值,因为序列化不会将值分配给静态或瞬态字段。