我遇到了Java序列化问题。假设我有一个Object持久化到文件系统。我们如何根据后一版本中的对象结构修改来更新文件的结构?
例如,如果我保存了对象
A{int a; String b} to file
我将结构更改为A{int a; String b, char c}
是否有任何方法可以根据后一版本的A更改以前保存的文件?
答案 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工具。