1

我遇到了 Java 序列化的问题。假设我有一个对象持久化到文件系统。我们如何根据后一个版本中的对象结构修改来更新文件的结构?

例如,如果我保存了 Object

A{int a; String b} to file

我改变了一个结构,A{int a; String b, char c}有什么办法可以根据 A 的后一版本更改以前保存的文件?

4

2 回答 2

2

这是可能的。您需要使下一个版本与以前的版本向后兼容。Java 序列化规范中解释了执行此操作的方法:http: //docs.oracle.com/javase/1.3/docs/guide/serialization/spec/version.doc.html

然而,这个问题是一个很好的例子,说明为什么使用本机 Java 序列化来长时间持久化对象通常是一个坏主意。如果您使用了特定格式(XML、JSON 或其他格式),您可以轻松读取和转换文件本身,或者能够读取具有不同序列化程序实现的文件的任何版本,从而更轻松地从一个版本迁移给另一个。

于 2012-04-30T10:42:29.770 回答
1

是的(只要结构不太不同并遵守某些规则)。假设您的文件包含以下内容的序列化表示:

class Foo
{
  int a;                        // value = 42
  String b;                     // value = "don't panic"
}

但是,您现在已经更改了Foo对象,并且类定义现在是:

class Foo
{
   int a;
   String b;
   char c;
}

当读入你的文件时,序列化机制会自动弹出一个实例Foo,并将 a 设置为 42,将 b 设置为“不要恐慌”。for 的值c不在流中,因此默认情况下,它被设置为 Java 默认值(在本例中,对于 char,0x0000)。

现在你有了你的对象,你可以设置值c

foo.c = 'Z';

如果您现在序列化您的对象并将其写入文件,则该文件将具有以下序列化表示:

class Foo
{
  int a;                        // value = 42
  String b;                     // value = "don't panic"
  char c;                       // value = 'Z'
}

正如我们在上面看到的,c当在对象流中找不到它时,它被赋予了一个默认值。您可能想要定义不同的默认值。序列化机制为您在序列化/反序列化时执行自定义代码提供了一种方式。有关详细信息,请查看用于 Serializable的Javadoc (参见 的描述readObject())。


编辑:正如 JB Nizet 指出的那样,有一个特殊的序列化字段称为serialVersionUID. 您需要确保对象中的版本 ID 与对象流中的内容相匹配。您可以像这样在对象中显式设置它:

private static final long serialVersionUID = 1L;

但是,如果您最初没有指定它,它会使用从字段和方法签名的哈希算法生成的值自动写出。如果你需要重新生成这个数字(这样你就可以在你的类中将它定义为一个常量,你需要使用serialver工具。

于 2012-04-30T10:41:39.690 回答