SerializationVersionId相同,但类被修改?

时间:2013-10-03 17:04:50

标签: java serialization

我序列化一个对象并通过网络传输它。我的序列化类对象有serilizableId我自己定义。现在在另一个JVM中我保持SeriliazibleId相同但改变了一些属性。 会发生什么以及为什么?它能够反序列化吗?

2 个答案:

答案 0 :(得分:1)

您必须参考Java对象序列化规范here

具体而言,您允许做什么:

  • 删除字段 - 如果在类中删除某个字段,则写入的流将不包含其值。当流由较早的类读取时,该字段的值将设置为默认值,因为流中没有可用的值。但是,此默认值可能会对早期版本履行合同的能力产生不利影响。
  • 在层次结构中向上或向下移动类 - 由于流中的数据显示的顺序错误,因此不允许这样做。
  • 将非静态字段更改为静态字段或非瞬态字段更改为瞬态 - 依赖于默认序列化时,此更改等同于从类中删除字段。此类版本不会将该数据写入流中,因此该类的早期版本无法读取该数据。与删除字段时一样,早期版本的字段将初始化为默认值,这可能导致类以意外方式失败。
  • 更改原始字段的声明类型 - 该类的每个版本都使用其声明的类型写入数据。尝试读取该字段的类的早期版本将失败,因为流中的数据类型与字段的类型不匹配。
  • 更改writeObject或readObject方法,使其不再写入或读取默认字段数据或更改它,以便在先前版本没有时尝试写入或读取它。默认字段数据必须始终显示或不显示在流中。
  • 将类从Serializable更改为Externalizable或反之亦然是一种不兼容的更改,因为流将包含与可用类的实现不兼容的数据。
  • 将类从非枚举类型更改为枚举类型,反之亦然,因为流将包含与可用类的实现不兼容的数据。
  • 删除Serializable或Externalizable是一种不兼容的更改,因为在编写时它将不再提供该类旧版本所需的字段。
  • 如果行为会产生与该类的任何旧版本不兼容的对象,则将writeReplace或readResolve方法添加到类中是不兼容的。

你可以改为做什么:

  • 添加字段 - 当重构的类具有未在流中出现的字段时,对象中的该字段将初始化为其类型的默认值。如果需要特定于类的初始化,则该类可以提供readObject方法,该方法可以将字段初始化为非默认值。
  • 添加类 - 流将包含流中每个对象的类型层次结构。将流中的此层次结构与当前类进行比较可以检测其他类。由于流中没有信息来初始化对象,因此类的字段将初始化为默认值。
  • 删除类 - 将流中的类层次结构与当前类的类层次结构进行比较可以检测到类已被删除。在这种情况下,从流中读取与该类对应的字段和对象。将丢弃原始字段,但会创建已删除类引用的对象,因为它们稍后可能会在流中引用。当流被垃圾收集或重置时,它们将被垃圾收集。
  • 添加writeObject / readObject方法 - 如果读取流的版本具有这些方法,则像往常一样,readObject需要读取默认序列化写入流所需的数据。它应该在读取任何可选数据之前先调用defaultReadObject。期望writeObject方法像往常一样调用defaultWriteObject来写入所需的数据,然后可以编写可选数据。
  • 删除writeObject / readObject方法 - 如果读取流的类没有这些方法,则默认序列化将读取所需数据,并且将丢弃可选数据。
  • 添加java.io.Serializable - 这相当于添加类型。此类的流中没有值,因此其字段将初始化为默认值。对非可序列化类的子类化的支持要求类的超类型具有无参数构造函数,并且类本身将被初始化为默认值。如果no-arg构造函数不可用,则抛出InvalidClassException。
  • 更改对字段的访问权限 - 访问修饰符public,package,protected和private不会影响序列化为字段赋值的能力。
  • 将字段从静态更改为非静态或瞬态更改为非瞬态 - 当依赖默认序列化来计算可序列化字段时,此更改等同于向类添加字段。新字段将写入流,但较早的类将忽略该值,因为序列化不会将值分配给静态或瞬态字段。

答案 1 :(得分:0)

如果您在课程中使用private static final long serialVersionUID;,那么您确保任何版本更改直到它们向后兼容会影响你的课程的反序列化。如果它不向后兼容,那么您需要增加串行版本ID。