0

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

4

2 回答 2

1

您必须在此处参考 Java 对象序列化规范。

具体来说,您不允许做的事情:

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

您可以改为:

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

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

于 2013-10-03T17:56:58.210 回答