如何更新持久化Java对象的结构?

时间:2012-04-30 10:35:50

标签: java serialization

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

例如,如果我保存了对象

A{int a; String b} to file

我将结构更改为A{int a; String b, char c}是否有任何方法可以根据后一版本的A更改以前保存的文件?

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

是(只要结构不是不同而且obeys certain rules)。假设您的文件包含序列化表示形式:

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设置为“不要惊慌”。 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在对象流中找不到时会得到默认值。您可能想要定义不同的默认值。序列化机制为您提供了一种在序列化/反序列化时执行自定义代码的方法。有关详细信息,请查看Javadoc for Serializable(请参阅readObject()的说明)。


编辑:正如JB Nizet指出的那样,有一个名为serialVersionUID的特殊序列化字段。您需要确保对象中的版本ID与对象流中的版本ID匹配。您可以在对象中明确设置它,如下所示:

private static final long serialVersionUID = 1L;

但是,如果您最初没有指定它,则会使用从字段和方法签名的哈希算法生成的值自动写出。如果您需要重新生成此数字(因此您可以将其定义为班级中的常量,则需要使用serialver工具。